[01/14] crypto: ecdsa - Convert byte arrays with key coordinates to digits

Message ID 20240208221840.3665874-2-stefanb@linux.ibm.com
State New
Headers
Series Add support for NIST P521 to ecdsa and ecdh |

Commit Message

Stefan Berger Feb. 8, 2024, 10:18 p.m. UTC
  For NIST P192/256/384 the public key's x and y parameters could be copied
directly from a given array since both parameters each filled 'ndigits'
of digits (a 'digit' is a u64). For support of NIST P521 the key parameters
first have to be copied right-aligned into a temporary byte array and can
then be copied into the final digit array using ecc_swap_digits.

Implement ecc_digits_from_array to convert a byte array into an array of
digits and use this function in ecdsa_set_pub_key where an input byte array
needs to be converted into digits.

Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
---
 crypto/ecdsa.c                | 15 ++++++++++-----
 include/crypto/internal/ecc.h | 19 +++++++++++++++++++
 2 files changed, 29 insertions(+), 5 deletions(-)
  

Comments

kernel test robot Feb. 9, 2024, 7:36 p.m. UTC | #1
Hi Stefan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on herbert-crypto-2.6/master linus/master v6.8-rc3 next-20240209]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Stefan-Berger/crypto-ecdsa-Convert-byte-arrays-with-key-coordinates-to-digits/20240209-062415
base:   https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
patch link:    https://lore.kernel.org/r/20240208221840.3665874-2-stefanb%40linux.ibm.com
patch subject: [PATCH 01/14] crypto: ecdsa - Convert byte arrays with key coordinates to digits
config: x86_64-randconfig-101-20240209 (https://download.01.org/0day-ci/archive/20240210/202402100352.1TagPxg9-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240210/202402100352.1TagPxg9-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202402100352.1TagPxg9-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> crypto/ecdsa.c:225:34: warning: variable 'nbytes' set but not used [-Wunused-but-set-variable]
     225 |         unsigned int digitlen, ndigits, nbytes;
         |                                         ^
   1 warning generated.


vim +/nbytes +225 crypto/ecdsa.c

   216	
   217	/*
   218	 * Set the public key given the raw uncompressed key data from an X509
   219	 * certificate. The key data contain the concatenated X and Y coordinates of
   220	 * the public key.
   221	 */
   222	static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen)
   223	{
   224		struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
 > 225		unsigned int digitlen, ndigits, nbytes;
   226		const unsigned char *d = key;
   227		int ret;
   228	
   229		ret = ecdsa_ecc_ctx_reset(ctx);
   230		if (ret < 0)
   231			return ret;
   232	
   233		if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u64)) != 0)
   234			return -EINVAL;
   235		/* we only accept uncompressed format indicated by '4' */
   236		if (d[0] != 4)
   237			return -EINVAL;
   238	
   239		keylen--;
   240		digitlen = keylen >> 1;
   241	
   242		ndigits = digitlen / sizeof(u64);
   243		if (ndigits != ctx->curve->g.ndigits)
   244			return -EINVAL;
   245	
   246		nbytes = ndigits * sizeof(u64);
   247		d++;
   248	
   249		ecc_digits_from_array(d, digitlen, ctx->pub_key.x, ndigits);
   250		ecc_digits_from_array(&d[digitlen], digitlen, ctx->pub_key.y, ndigits);
   251	
   252		ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key);
   253	
   254		ctx->pub_key_set = ret == 0;
   255	
   256		return ret;
   257	}
   258
  

Patch

diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c
index fbd76498aba8..c3748ddc9964 100644
--- a/crypto/ecdsa.c
+++ b/crypto/ecdsa.c
@@ -222,9 +222,8 @@  static int ecdsa_ecc_ctx_reset(struct ecc_ctx *ctx)
 static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen)
 {
 	struct ecc_ctx *ctx = akcipher_tfm_ctx(tfm);
+	unsigned int digitlen, ndigits, nbytes;
 	const unsigned char *d = key;
-	const u64 *digits = (const u64 *)&d[1];
-	unsigned int ndigits;
 	int ret;
 
 	ret = ecdsa_ecc_ctx_reset(ctx);
@@ -238,12 +237,18 @@  static int ecdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsig
 		return -EINVAL;
 
 	keylen--;
-	ndigits = (keylen >> 1) / sizeof(u64);
+	digitlen = keylen >> 1;
+
+	ndigits = digitlen / sizeof(u64);
 	if (ndigits != ctx->curve->g.ndigits)
 		return -EINVAL;
 
-	ecc_swap_digits(digits, ctx->pub_key.x, ndigits);
-	ecc_swap_digits(&digits[ndigits], ctx->pub_key.y, ndigits);
+	nbytes = ndigits * sizeof(u64);
+	d++;
+
+	ecc_digits_from_array(d, digitlen, ctx->pub_key.x, ndigits);
+	ecc_digits_from_array(&d[digitlen], digitlen, ctx->pub_key.y, ndigits);
+
 	ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key);
 
 	ctx->pub_key_set = ret == 0;
diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h
index 4f6c1a68882f..ee6886547fd1 100644
--- a/include/crypto/internal/ecc.h
+++ b/include/crypto/internal/ecc.h
@@ -56,6 +56,25 @@  static inline void ecc_swap_digits(const void *in, u64 *out, unsigned int ndigit
 		out[i] = get_unaligned_be64(&src[ndigits - 1 - i]);
 }
 
+/**
+ * ecc_digits_from_array() - Create ndigits from a byte array of nbytes
+ * @in:       Input byte array
+ * @nbytes    Size of input byte array
+ * @out       Output digits array
+ * @ndigits:  Number of digits to create from byte array
+ */
+static inline void ecc_digits_from_array(const u8 *in, unsigned int nbytes,
+					 u64 *out, unsigned int ndigits)
+{
+	unsigned int sz = ndigits * sizeof(u64);
+	u8 tmp[ECC_MAX_DIGITS * sizeof(u64)];
+	unsigned int o = sz - nbytes;
+
+	memset(tmp, 0, o);
+	memcpy(&tmp[o], in, nbytes);
+	ecc_swap_digits(tmp, out, ndigits);
+}
+
 /**
  * ecc_is_key_valid() - Validate a given ECDH private key
  *