|
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, ¶ms->key_size, sizeof(params->key_size));
|
|
Torsten Duwe |
44e69f |
ptr = dh_pack_data(ptr, ¶ms->p_size, sizeof(params->p_size));
|
|
Torsten Duwe |
44e69f |
+ ptr = dh_pack_data(ptr, ¶ms->q_size, sizeof(params->q_size));
|
|
Torsten Duwe |
44e69f |
ptr = dh_pack_data(ptr, ¶ms->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(¶ms->key_size, ptr, sizeof(params->key_size));
|
|
Torsten Duwe |
44e69f |
ptr = dh_unpack_data(¶ms->p_size, ptr, sizeof(params->p_size));
|
|
Torsten Duwe |
44e69f |
+ ptr = dh_unpack_data(¶ms->q_size, ptr, sizeof(params->q_size));
|
|
Torsten Duwe |
44e69f |
ptr = dh_unpack_data(¶ms->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 |
|