Blob Blame History Raw
From: =?UTF-8?q?Stephan=20M=C3=BCller?= <smueller@chronox.de>
Date: Mon, 20 Jul 2020 19:09:23 +0200
Subject: crypto: ecc - SP800-56A rev 3 local public key validation
Git-commit: 6914dd53eb7af7cbc66edf7992d600b1e952c40d
Patch-mainline: v5.9-rc1
References: bsc#1175718

After the generation of a local public key, SP800-56A rev 3 section
5.6.2.1.3 mandates a validation of that key with a full validation
compliant to section 5.6.2.3.3.

Only if the full validation passes, the key is allowed to be used.

The patch adds the full key validation compliant to 5.6.2.3.3 and
performs the required check on the generated public key.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
[ ptesarik: The export is needed only to share the routines with ecrdsa.
  SLE15 does not have the ecrdsa module, so the added function should be
  local to crypto/ecc.c. ]
Signed-off-by: Petr Tesarik <ptesarik@suse.com>
---
 crypto/ecc.c |   34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -42,6 +42,9 @@ typedef struct {
 	u64 m_high;
 } uint128_t;
 
+static int ecc_is_pubkey_valid_full(const struct ecc_curve *curve,
+				    struct ecc_point *pk);
+
 static inline const struct ecc_curve *ecc_get_curve(unsigned int curve_id)
 {
 	switch (curve_id) {
@@ -1404,7 +1407,9 @@ int ecc_make_pub_key(unsigned int curve_
 	}
 
 	ecc_point_mult(pk, &curve->g, priv, NULL, curve, ndigits);
-	if (ecc_point_is_zero(pk)) {
+
+	/* SP800-56A rev 3 5.6.2.1.3 key check */
+	if (ecc_is_pubkey_valid_full(curve, pk)) {
 		ret = -EAGAIN;
 		goto err_free_point;
 	}
@@ -1452,6 +1457,33 @@ int ecc_is_pubkey_valid_partial(const st
 }
 EXPORT_SYMBOL(ecc_is_pubkey_valid_partial);
 
+/* SP800-56A section 5.6.2.3.3 full verification */
+static int ecc_is_pubkey_valid_full(const struct ecc_curve *curve,
+				    struct ecc_point *pk)
+{
+	struct ecc_point *nQ;
+
+	/* Checks 1 through 3 */
+	int ret = ecc_is_pubkey_valid_partial(curve, pk);
+
+	if (ret)
+		return ret;
+
+	/* Check 4: Verify that nQ is the zero point. */
+	nQ = ecc_alloc_point(pk->ndigits);
+	if (!nQ)
+		return -ENOMEM;
+
+	ecc_point_mult(nQ, pk, curve->n, NULL, curve, pk->ndigits);
+	if (!ecc_point_is_zero(nQ))
+		ret = -EINVAL;
+
+	ecc_free_point(nQ);
+
+	return ret;
+}
+EXPORT_SYMBOL(ecc_is_pubkey_valid_full);
+
 int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
 			      const u64 *private_key, const u64 *public_key,
 			      u64 *secret)