Torsten Duwe 44e69f
Git-commit: e3fe0ae129622b78e710e75ecbf7aca7af5dda47
Torsten Duwe 44e69f
From: Stephan Mueller <smueller@chronox.de>
Torsten Duwe 44e69f
Date: Wed, 27 Jun 2018 08:15:31 +0200
Torsten Duwe 44e69f
Subject: [PATCH] crypto: dh - add public key verification test
Torsten Duwe 44e69f
Patch-mainline: v4.19-rc1
Torsten Duwe 44e69f
References: bsc#1155331
Torsten Duwe 44e69f
Torsten Duwe 44e69f
According to SP800-56A section 5.6.2.1, the public key to be processed
Torsten Duwe 44e69f
for the DH operation shall be checked for appropriateness. The check
Torsten Duwe 44e69f
shall covers the full verification test in case the domain parameter Q
Torsten Duwe 44e69f
is provided as defined in SP800-56A section 5.6.2.3.1. If Q is not
Torsten Duwe 44e69f
provided, the partial check according to SP800-56A section 5.6.2.3.2 is
Torsten Duwe 44e69f
performed.
Torsten Duwe 44e69f
Torsten Duwe 44e69f
The full verification test requires the presence of the domain parameter
Torsten Duwe 44e69f
Q. Thus, the patch adds the support to handle Q. It is permissible to
Torsten Duwe 44e69f
not provide the Q value as part of the domain parameters. This implies
Torsten Duwe 44e69f
that the interface is still backwards-compatible where so far only P and
Torsten Duwe 44e69f
G are to be provided. However, if Q is provided, it is imported.
Torsten Duwe 44e69f
Torsten Duwe 44e69f
Without the test, the NIST ACVP testing fails. After adding this check,
Torsten Duwe 44e69f
the NIST ACVP testing passes. Testing without providing the Q domain
Torsten Duwe 44e69f
parameter has been performed to verify the interface has not changed.
Torsten Duwe 44e69f
Torsten Duwe 44e69f
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Torsten Duwe 44e69f
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Torsten Duwe 44e69f
Signed-off-by: Torsten Duwe <duwe@suse.de>
Torsten Duwe 44e69f
---
Torsten Duwe 44e69f
 crypto/dh.c         | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++---
Torsten Duwe 44e69f
 crypto/dh_helper.c  | 15 +++++++++---
Torsten Duwe 44e69f
 include/crypto/dh.h |  4 ++++
Torsten Duwe 44e69f
 3 files changed, 79 insertions(+), 6 deletions(-)
Torsten Duwe 44e69f
Torsten Duwe 44e69f
--- a/crypto/dh.c
Torsten Duwe 44e69f
+++ b/crypto/dh.c
Torsten Duwe 44e69f
@@ -16,14 +16,16 @@
Torsten Duwe 44e69f
 #include <linux/mpi.h>
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 struct dh_ctx {
Torsten Duwe 44e69f
-	MPI p;
Torsten Duwe 44e69f
-	MPI g;
Torsten Duwe 44e69f
-	MPI xa;
Torsten Duwe 44e69f
+	MPI p;	/* Value is guaranteed to be set. */
Torsten Duwe 44e69f
+	MPI q;	/* Value is optional. */
Torsten Duwe 44e69f
+	MPI g;	/* Value is guaranteed to be set. */
Torsten Duwe 44e69f
+	MPI xa;	/* Value is guaranteed to be set. */
Torsten Duwe 44e69f
 };
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 static void dh_clear_ctx(struct dh_ctx *ctx)
Torsten Duwe 44e69f
 {
Torsten Duwe 44e69f
 	mpi_free(ctx->p);
Torsten Duwe 44e69f
+	mpi_free(ctx->q);
Torsten Duwe 44e69f
 	mpi_free(ctx->g);
Torsten Duwe 44e69f
 	mpi_free(ctx->xa);
Torsten Duwe 44e69f
 	memset(ctx, 0, sizeof(*ctx));
Torsten Duwe 44e69f
@@ -63,6 +65,12 @@ static int dh_set_params(struct dh_ctx *
Torsten Duwe 44e69f
 	if (!ctx->p)
Torsten Duwe 44e69f
 		return -EINVAL;
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
+	if (params->q && params->q_size) {
Torsten Duwe 44e69f
+		ctx->q = mpi_read_raw_data(params->q, params->q_size);
Torsten Duwe 44e69f
+		if (!ctx->q)
Torsten Duwe 44e69f
+			return -EINVAL;
Torsten Duwe 44e69f
+	}
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
 	ctx->g = mpi_read_raw_data(params->g, params->g_size);
Torsten Duwe 44e69f
 	if (!ctx->g)
Torsten Duwe 44e69f
 		return -EINVAL;
Torsten Duwe 44e69f
@@ -96,6 +104,55 @@ err_clear_ctx:
Torsten Duwe 44e69f
 	return -EINVAL;
Torsten Duwe 44e69f
 }
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
+/*
Torsten Duwe 44e69f
+ * SP800-56A public key verification:
Torsten Duwe 44e69f
+ *
Torsten Duwe 44e69f
+ * * If Q is provided as part of the domain paramenters, a full validation
Torsten Duwe 44e69f
+ *   according to SP800-56A section 5.6.2.3.1 is performed.
Torsten Duwe 44e69f
+ *
Torsten Duwe 44e69f
+ * * If Q is not provided, a partial validation according to SP800-56A section
Torsten Duwe 44e69f
+ *   5.6.2.3.2 is performed.
Torsten Duwe 44e69f
+ */
Torsten Duwe 44e69f
+static int dh_is_pubkey_valid(struct dh_ctx *ctx, MPI y)
Torsten Duwe 44e69f
+{
Torsten Duwe 44e69f
+	if (unlikely(!ctx->p))
Torsten Duwe 44e69f
+		return -EINVAL;
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+	/*
Torsten Duwe 44e69f
+	 * Step 1: Verify that 2 <= y <= p - 2.
Torsten Duwe 44e69f
+	 *
Torsten Duwe 44e69f
+	 * The upper limit check is actually y < p instead of y < p - 1
Torsten Duwe 44e69f
+	 * as the mpi_sub_ui function is yet missing.
Torsten Duwe 44e69f
+	 */
Torsten Duwe 44e69f
+	if (mpi_cmp_ui(y, 1) < 1 || mpi_cmp(y, ctx->p) >= 0)
Torsten Duwe 44e69f
+		return -EINVAL;
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+	/* Step 2: Verify that 1 = y^q mod p */
Torsten Duwe 44e69f
+	if (ctx->q) {
Torsten Duwe 44e69f
+		MPI val = mpi_alloc(0);
Torsten Duwe 44e69f
+		int ret;
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+		if (!val)
Torsten Duwe 44e69f
+			return -ENOMEM;
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+		ret = mpi_powm(val, y, ctx->q, ctx->p);
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+		if (ret) {
Torsten Duwe 44e69f
+			mpi_free(val);
Torsten Duwe 44e69f
+			return ret;
Torsten Duwe 44e69f
+		}
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+		ret = mpi_cmp_ui(val, 1);
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+		mpi_free(val);
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+		if (ret != 0)
Torsten Duwe 44e69f
+			return -EINVAL;
Torsten Duwe 44e69f
+	}
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
+	return 0;
Torsten Duwe 44e69f
+}
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
 static int dh_compute_value(struct kpp_request *req)
Torsten Duwe 44e69f
 {
Torsten Duwe 44e69f
 	struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
Torsten Duwe 44e69f
@@ -118,6 +175,9 @@ static int dh_compute_value(struct kpp_r
Torsten Duwe 44e69f
 			ret = -EINVAL;
Torsten Duwe 44e69f
 			goto err_free_val;
Torsten Duwe 44e69f
 		}
Torsten Duwe 44e69f
+		ret = dh_is_pubkey_valid(ctx, base);
Torsten Duwe 44e69f
+		if (ret)
Torsten Duwe 44e69f
+			goto err_free_val;
Torsten Duwe 44e69f
 	} else {
Torsten Duwe 44e69f
 		base = ctx->g;
Torsten Duwe 44e69f
 	}
Torsten Duwe 44e69f
--- a/crypto/dh_helper.c
Torsten Duwe 44e69f
+++ b/crypto/dh_helper.c
Torsten Duwe 44e69f
@@ -30,7 +30,7 @@ static inline const u8 *dh_unpack_data(v
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 static inline int dh_data_size(const struct dh *p)
Torsten Duwe 44e69f
 {
Torsten Duwe 44e69f
-	return p->key_size + p->p_size + p->g_size;
Torsten Duwe 44e69f
+	return p->key_size + p->p_size + p->q_size + p->g_size;
Torsten Duwe 44e69f
 }
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 int crypto_dh_key_len(const struct dh *p)
Torsten Duwe 44e69f
@@ -56,9 +56,11 @@ int crypto_dh_encode_key(char *buf, unsi
Torsten Duwe 44e69f
 	ptr = dh_pack_data(ptr, &secret, sizeof(secret));
Torsten Duwe 44e69f
 	ptr = dh_pack_data(ptr, &params->key_size, sizeof(params->key_size));
Torsten Duwe 44e69f
 	ptr = dh_pack_data(ptr, &params->p_size, sizeof(params->p_size));
Torsten Duwe 44e69f
+	ptr = dh_pack_data(ptr, &params->q_size, sizeof(params->q_size));
Torsten Duwe 44e69f
 	ptr = dh_pack_data(ptr, &params->g_size, sizeof(params->g_size));
Torsten Duwe 44e69f
 	ptr = dh_pack_data(ptr, params->key, params->key_size);
Torsten Duwe 44e69f
 	ptr = dh_pack_data(ptr, params->p, params->p_size);
Torsten Duwe 44e69f
+	ptr = dh_pack_data(ptr, params->q, params->q_size);
Torsten Duwe 44e69f
 	dh_pack_data(ptr, params->g, params->g_size);
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 	return 0;
Torsten Duwe 44e69f
@@ -79,6 +81,7 @@ int crypto_dh_decode_key(const char *buf
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 	ptr = dh_unpack_data(&params->key_size, ptr, sizeof(params->key_size));
Torsten Duwe 44e69f
 	ptr = dh_unpack_data(&params->p_size, ptr, sizeof(params->p_size));
Torsten Duwe 44e69f
+	ptr = dh_unpack_data(&params->q_size, ptr, sizeof(params->q_size));
Torsten Duwe 44e69f
 	ptr = dh_unpack_data(&params->g_size, ptr, sizeof(params->g_size));
Torsten Duwe 44e69f
 	if (secret.len != crypto_dh_key_len(params))
Torsten Duwe 44e69f
 		return -EINVAL;
Torsten Duwe 44e69f
@@ -88,7 +91,7 @@ int crypto_dh_decode_key(const char *buf
Torsten Duwe 44e69f
 	 * some drivers assume otherwise.
Torsten Duwe 44e69f
 	 */
Torsten Duwe 44e69f
 	if (params->key_size > params->p_size ||
Torsten Duwe 44e69f
-	    params->g_size > params->p_size)
Torsten Duwe 44e69f
+	    params->g_size > params->p_size || params->q_size > params->p_size)
Torsten Duwe 44e69f
 		return -EINVAL;
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 	/* Don't allocate memory. Set pointers to data within
Torsten Duwe 44e69f
@@ -96,7 +99,9 @@ int crypto_dh_decode_key(const char *buf
Torsten Duwe 44e69f
 	 */
Torsten Duwe 44e69f
 	params->key = (void *)ptr;
Torsten Duwe 44e69f
 	params->p = (void *)(ptr + params->key_size);
Torsten Duwe 44e69f
-	params->g = (void *)(ptr + params->key_size + params->p_size);
Torsten Duwe 44e69f
+	params->q = (void *)(ptr + params->key_size + params->p_size);
Torsten Duwe 44e69f
+	params->g = (void *)(ptr + params->key_size + params->p_size +
Torsten Duwe 44e69f
+			     params->q_size);
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
 	/*
Torsten Duwe 44e69f
 	 * Don't permit 'p' to be 0.  It's not a prime number, and it's subject
Torsten Duwe 44e69f
@@ -106,6 +111,10 @@ int crypto_dh_decode_key(const char *buf
Torsten Duwe 44e69f
 	if (memchr_inv(params->p, 0, params->p_size) == NULL)
Torsten Duwe 44e69f
 		return -EINVAL;
Torsten Duwe 44e69f
 
Torsten Duwe 44e69f
+	/* It is permissible to not provide Q. */
Torsten Duwe 44e69f
+	if (params->q_size == 0)
Torsten Duwe 44e69f
+		params->q = NULL;
Torsten Duwe 44e69f
+
Torsten Duwe 44e69f
 	return 0;
Torsten Duwe 44e69f
 }
Torsten Duwe 44e69f
 EXPORT_SYMBOL_GPL(crypto_dh_decode_key);
Torsten Duwe 44e69f
--- a/include/crypto/dh.h
Torsten Duwe 44e69f
+++ b/include/crypto/dh.h
Torsten Duwe 44e69f
@@ -29,17 +29,21 @@
Torsten Duwe 44e69f
  *
Torsten Duwe 44e69f
  * @key:	Private DH key
Torsten Duwe 44e69f
  * @p:		Diffie-Hellman parameter P
Torsten Duwe 44e69f
+ * @q:		Diffie-Hellman parameter Q
Torsten Duwe 44e69f
  * @g:		Diffie-Hellman generator G
Torsten Duwe 44e69f
  * @key_size:	Size of the private DH key
Torsten Duwe 44e69f
  * @p_size:	Size of DH parameter P
Torsten Duwe 44e69f
+ * @q_size:	Size of DH parameter Q
Torsten Duwe 44e69f
  * @g_size:	Size of DH generator G
Torsten Duwe 44e69f
  */
Torsten Duwe 44e69f
 struct dh {
Torsten Duwe 44e69f
 	void *key;
Torsten Duwe 44e69f
 	void *p;
Torsten Duwe 44e69f
+	void *q;
Torsten Duwe 44e69f
 	void *g;
Torsten Duwe 44e69f
 	unsigned int key_size;
Torsten Duwe 44e69f
 	unsigned int p_size;
Torsten Duwe 44e69f
+	unsigned int q_size;
Torsten Duwe 44e69f
 	unsigned int g_size;
Torsten Duwe 44e69f
 };
Torsten Duwe 44e69f