* [PATCH v2 00/19] Add ECDSA support for FIT image verification @ 2024-08-01 5:57 Sascha Hauer 2024-08-01 5:57 ` [PATCH v2 01/19] errno: include string for EOPNOTSUPP Sascha Hauer ` (19 more replies) 0 siblings, 20 replies; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List This series implements ECDSA signature verification for FIT images. The ECDSA code itself is taken from the Kernel. Currently only supported way to specify a ECDSA key is to compile it into the binary using CONFIG_CRYPTO_ECDSA_KEY, taking it from a device tree is not ye supported. Changes since v1: - better split up rsatoc patches - keep engine support around in rsatoc as it is still needed in many cases - Add more cleanup to rsatoc Sascha Hauer (19): errno: include string for EOPNOTSUPP rsatoc: disable deprecated function warnings rsatoc: remove unnecessary function call rsatoc: pass EVP_PKEY around rsatoc: rename rsa_err() to openssl_error() rsatoc: move engine initialization to engine_get_pub_key() rsatoc: cleanup error handling rsatoc: remove unnecessary error check rsatoc: use non deprecated openssl functions to retrieve RSA params rsatoc: check error value of gen_key() rsatoc: rename to keytoc keytoc: add ecdsa support keytoc: Let openssl_error() take a format string keytoc: clarify error messages malloc: implement free_sensitive() Add elliptic curve cryptography (ECC) helper functions crypto: add ECDSA support crypto: make RSA a visible option fit: Add ecdsa support common/Kconfig | 1 - common/dlmalloc.c | 15 + common/image-fit.c | 113 +- common/misc.c | 1 + common/tlsf_malloc.c | 11 + crypto/Kconfig | 28 +- crypto/Makefile | 22 +- crypto/ecc.c | 1661 +++++++++++++++++++++++++++++ crypto/ecc_curve_defs.h | 155 +++ crypto/ecdsa.c | 169 +++ include/asm-generic/barebox.lds.h | 7 + include/crypto/ecc_curve.h | 62 ++ include/crypto/ecdh.h | 83 ++ include/crypto/internal/ecc.h | 278 +++++ include/dma.h | 5 + include/ecdsa.h | 21 + include/linux/slab.h | 5 + include/malloc.h | 1 + scripts/.gitignore | 2 +- scripts/Kconfig | 4 +- scripts/Makefile | 6 +- scripts/Makefile.lib | 12 +- scripts/{rsatoc.c => keytoc.c} | 458 +++++--- test/self/Makefile | 2 +- 24 files changed, 2924 insertions(+), 198 deletions(-) create mode 100644 crypto/ecc.c create mode 100644 crypto/ecc_curve_defs.h create mode 100644 crypto/ecdsa.c create mode 100644 include/crypto/ecc_curve.h create mode 100644 include/crypto/ecdh.h create mode 100644 include/crypto/internal/ecc.h create mode 100644 include/ecdsa.h rename scripts/{rsatoc.c => keytoc.c} (61%) -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 01/19] errno: include string for EOPNOTSUPP 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:28 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 02/19] rsatoc: disable deprecated function warnings Sascha Hauer ` (18 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List -EOPNOTSUPP is becoming more common in the barebox code, so include the error string for it in the image. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- common/misc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/common/misc.c b/common/misc.c index 7bc92c0f95..e6e993338c 100644 --- a/common/misc.c +++ b/common/misc.c @@ -59,6 +59,7 @@ const char *strerror(int errnum) case EPROBE_DEFER : str = "Requested probe deferral"; break; case ELOOP : str = "Too many symbolic links encountered"; break; case ENODATA : str = "No data available"; break; + case EOPNOTSUPP : str = "Operation not supported"; break; #if 0 /* These are probably not needed */ case ENOTBLK : str = "Block device required"; break; case EFBIG : str = "File too large"; break; -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 01/19] errno: include string for EOPNOTSUPP 2024-08-01 5:57 ` [PATCH v2 01/19] errno: include string for EOPNOTSUPP Sascha Hauer @ 2024-08-05 9:28 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:28 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > -EOPNOTSUPP is becoming more common in the barebox code, so include the > error string for it in the image. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > common/misc.c | 1 + Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > 1 file changed, 1 insertion(+) > > diff --git a/common/misc.c b/common/misc.c > index 7bc92c0f95..e6e993338c 100644 > --- a/common/misc.c > +++ b/common/misc.c > @@ -59,6 +59,7 @@ const char *strerror(int errnum) > case EPROBE_DEFER : str = "Requested probe deferral"; break; > case ELOOP : str = "Too many symbolic links encountered"; break; > case ENODATA : str = "No data available"; break; > + case EOPNOTSUPP : str = "Operation not supported"; break; > #if 0 /* These are probably not needed */ > case ENOTBLK : str = "Block device required"; break; > case EFBIG : str = "File too large"; break; -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 02/19] rsatoc: disable deprecated function warnings 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer 2024-08-01 5:57 ` [PATCH v2 01/19] errno: include string for EOPNOTSUPP Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:29 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 03/19] rsatoc: remove unnecessary function call Sascha Hauer ` (17 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List In rsatoc we use several deprecated functions. We can get rid of some of them in the next few patches, but we will still need the ENGINE functions as the provider API is not yet widespread across distributions. Disable the deprecated function warnings for now. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index d5943d4a11..ed167bf247 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -5,6 +5,7 @@ * This tool converts an RSA key given as file or PKCS#11 * URI to a C struct suitable to compile with barebox. */ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include <stdio.h> #include <string.h> #include <time.h> -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 02/19] rsatoc: disable deprecated function warnings 2024-08-01 5:57 ` [PATCH v2 02/19] rsatoc: disable deprecated function warnings Sascha Hauer @ 2024-08-05 9:29 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:29 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > In rsatoc we use several deprecated functions. We can get rid of some > of them in the next few patches, but we will still need the ENGINE > functions as the provider API is not yet widespread across > distributions. Disable the deprecated function warnings for now. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index d5943d4a11..ed167bf247 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -5,6 +5,7 @@ > * This tool converts an RSA key given as file or PKCS#11 > * URI to a C struct suitable to compile with barebox. > */ > +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" > #include <stdio.h> > #include <string.h> > #include <time.h> -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 03/19] rsatoc: remove unnecessary function call 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer 2024-08-01 5:57 ` [PATCH v2 01/19] errno: include string for EOPNOTSUPP Sascha Hauer 2024-08-01 5:57 ` [PATCH v2 02/19] rsatoc: disable deprecated function warnings Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:29 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 04/19] rsatoc: pass EVP_PKEY around Sascha Hauer ` (16 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List Calling ENGINE_set_default_RSA() doesn't seem appropriate for upcoming ECDSA support. I don't know what the call is good for, it works without it, so remove it. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index ed167bf247..37728899f8 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -289,12 +289,6 @@ static int rsa_engine_init(ENGINE **pe) } } - if (!ENGINE_set_default_RSA(e)) { - fprintf(stderr, "Couldn't set engine as default for RSA\n"); - ret = -1; - goto err_set_rsa; - } - *pe = e; return 0; -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 03/19] rsatoc: remove unnecessary function call 2024-08-01 5:57 ` [PATCH v2 03/19] rsatoc: remove unnecessary function call Sascha Hauer @ 2024-08-05 9:29 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:29 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > Calling ENGINE_set_default_RSA() doesn't seem appropriate for upcoming > ECDSA support. I don't know what the call is good for, it works without > it, so remove it. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 6 ------ > 1 file changed, 6 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index ed167bf247..37728899f8 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -289,12 +289,6 @@ static int rsa_engine_init(ENGINE **pe) > } > } > > - if (!ENGINE_set_default_RSA(e)) { > - fprintf(stderr, "Couldn't set engine as default for RSA\n"); > - ret = -1; > - goto err_set_rsa; > - } > - > *pe = e; > > return 0; -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 04/19] rsatoc: pass EVP_PKEY around 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (2 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 03/19] rsatoc: remove unnecessary function call Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:35 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 05/19] rsatoc: rename rsa_err() to openssl_error() Sascha Hauer ` (15 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List rsa_pem_get_pub_key() and rsa_engine_get_pub_key() both return a RSA *. Return a EVP_PKEY * instead and only convert it into a RSA * in rsa_get_params(). Also drop the rsa_ prefix from the function name as they are no longer rsa specific. This is done in preparation for adding ECDSA support later. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 79 +++++++++++++++++------------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 37728899f8..462963424a 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -33,25 +33,24 @@ static int rsa_err(const char *msg) } /** - * rsa_pem_get_pub_key() - read a public key from a .crt file + * pem_get_pub_key() - read a public key from a .crt file * * @keydir: Directory containins the key * @name Name of key file (will have a .crt extension) - * @rsap Returns RSA object, or NULL on failure + * @key Returns key object, or NULL on failure * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) */ -static int rsa_pem_get_pub_key(const char *path, RSA **rsap) +static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) { EVP_PKEY *key; X509 *cert; - RSA *rsa; FILE *f; int ret; - *rsap = NULL; + *pkey = NULL; f = fopen(path, "r"); if (!f) { - fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n", + fprintf(stderr, "Couldn't open certificate: '%s': %s\n", path, strerror(errno)); return -EACCES; } @@ -76,22 +75,13 @@ static int rsa_pem_get_pub_key(const char *path, RSA **rsap) } } - /* Convert to a RSA_style key. */ - rsa = EVP_PKEY_get1_RSA(key); - if (!rsa) { - rsa_err("Couldn't convert to a RSA style key"); - ret = -EINVAL; - goto err_rsa; - } fclose(f); - EVP_PKEY_free(key); X509_free(cert); - *rsap = rsa; + + *pkey = key; return 0; -err_rsa: - EVP_PKEY_free(key); err_pubkey: X509_free(cert); err_cert: @@ -100,43 +90,22 @@ static int rsa_pem_get_pub_key(const char *path, RSA **rsap) } /** - * rsa_engine_get_pub_key() - read a public key from given engine + * engine_get_pub_key() - read a public key from given engine * * @keydir: Key prefix * @name Name of key * @engine Engine to use - * @rsap Returns RSA object, or NULL on failure + * @key Returns key object, or NULL on failure * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) */ -static int rsa_engine_get_pub_key(const char *key_id, - ENGINE *engine, RSA **rsap) +static int engine_get_pub_key(const char *key_id, + ENGINE *engine, EVP_PKEY **key) { - EVP_PKEY *key; - RSA *rsa; - int ret; - - *rsap = NULL; - - key = ENGINE_load_public_key(engine, key_id, NULL, NULL); - if (!key) + *key = ENGINE_load_public_key(engine, key_id, NULL, NULL); + if (!*key) return rsa_err("Failure loading public key from engine"); - /* Convert to a RSA_style key. */ - rsa = EVP_PKEY_get1_RSA(key); - if (!rsa) { - rsa_err("Couldn't convert to a RSA style key"); - ret = -EINVAL; - goto err_rsa; - } - - EVP_PKEY_free(key); - *rsap = rsa; - return 0; - -err_rsa: - EVP_PKEY_free(key); - return ret; } /* @@ -191,15 +160,23 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) /* * rsa_get_params(): - Get the important parameters of an RSA public key */ -static int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, +static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, BIGNUM **modulusp, BIGNUM **r_squaredp) { + RSA *rsa; BIGNUM *big1, *big2, *big32, *big2_32; BIGNUM *n, *r, *r_squared, *tmp; const BIGNUM *key_n; BN_CTX *bn_ctx = BN_CTX_new(); int ret = 0; + /* Convert to a RSA_style key. */ + rsa = EVP_PKEY_get1_RSA(key); + if (!rsa) { + rsa_err("Couldn't convert to a RSA style key"); + return -EINVAL; + } + /* Initialize BIGNUMs */ big1 = BN_new(); big2 = BN_new(); @@ -215,10 +192,10 @@ static int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, return -ENOMEM; } - if (0 != rsa_get_exponent(key, exponent)) + if (0 != rsa_get_exponent(rsa, exponent)) ret = -1; - RSA_get0_key(key, &key_n, NULL, NULL); + RSA_get0_key(rsa, &key_n, NULL, NULL); if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) ret = -1; @@ -384,7 +361,7 @@ static int gen_key(const char *keyname, const char *path) uint32_t n0_inv; int ret; int bits; - RSA *rsa; + EVP_PKEY *key; ENGINE *e = NULL; char *tmp, *key_name_c; @@ -410,16 +387,16 @@ static int gen_key(const char *keyname, const char *path) ret = rsa_engine_init(&e); if (ret) exit(1); - ret = rsa_engine_get_pub_key(path, e, &rsa); + ret = engine_get_pub_key(path, e, &key); if (ret) exit(1); } else { - ret = rsa_pem_get_pub_key(path, &rsa); + ret = pem_get_pub_key(path, &key); if (ret) exit(1); } - ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); + ret = rsa_get_params(key, &exponent, &n0_inv, &modulus, &r_squared); if (ret) return ret; -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 04/19] rsatoc: pass EVP_PKEY around 2024-08-01 5:57 ` [PATCH v2 04/19] rsatoc: pass EVP_PKEY around Sascha Hauer @ 2024-08-05 9:35 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:35 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > rsa_pem_get_pub_key() and rsa_engine_get_pub_key() both return a RSA *. > Return a EVP_PKEY * instead and only convert it into a RSA * in > rsa_get_params(). Also drop the rsa_ prefix from the function name as > they are no longer rsa specific. This is done in preparation for adding > ECDSA support later. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 79 +++++++++++++++++------------------------------- > 1 file changed, 28 insertions(+), 51 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index 37728899f8..462963424a 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -33,25 +33,24 @@ static int rsa_err(const char *msg) > } > > /** > - * rsa_pem_get_pub_key() - read a public key from a .crt file > + * pem_get_pub_key() - read a public key from a .crt file > * > * @keydir: Directory containins the key > * @name Name of key file (will have a .crt extension) > - * @rsap Returns RSA object, or NULL on failure > + * @key Returns key object, or NULL on failure > * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) > */ > -static int rsa_pem_get_pub_key(const char *path, RSA **rsap) > +static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > { > EVP_PKEY *key; > X509 *cert; > - RSA *rsa; > FILE *f; > int ret; > > - *rsap = NULL; > + *pkey = NULL; > f = fopen(path, "r"); > if (!f) { > - fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n", > + fprintf(stderr, "Couldn't open certificate: '%s': %s\n", > path, strerror(errno)); > return -EACCES; > } > @@ -76,22 +75,13 @@ static int rsa_pem_get_pub_key(const char *path, RSA **rsap) > } > } > > - /* Convert to a RSA_style key. */ > - rsa = EVP_PKEY_get1_RSA(key); > - if (!rsa) { > - rsa_err("Couldn't convert to a RSA style key"); > - ret = -EINVAL; > - goto err_rsa; > - } > fclose(f); > - EVP_PKEY_free(key); > X509_free(cert); > - *rsap = rsa; > + > + *pkey = key; > > return 0; > > -err_rsa: > - EVP_PKEY_free(key); > err_pubkey: > X509_free(cert); > err_cert: > @@ -100,43 +90,22 @@ static int rsa_pem_get_pub_key(const char *path, RSA **rsap) > } > > /** > - * rsa_engine_get_pub_key() - read a public key from given engine > + * engine_get_pub_key() - read a public key from given engine > * > * @keydir: Key prefix > * @name Name of key > * @engine Engine to use > - * @rsap Returns RSA object, or NULL on failure > + * @key Returns key object, or NULL on failure > * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) > */ > -static int rsa_engine_get_pub_key(const char *key_id, > - ENGINE *engine, RSA **rsap) > +static int engine_get_pub_key(const char *key_id, > + ENGINE *engine, EVP_PKEY **key) > { > - EVP_PKEY *key; > - RSA *rsa; > - int ret; > - > - *rsap = NULL; > - > - key = ENGINE_load_public_key(engine, key_id, NULL, NULL); > - if (!key) > + *key = ENGINE_load_public_key(engine, key_id, NULL, NULL); > + if (!*key) > return rsa_err("Failure loading public key from engine"); > > - /* Convert to a RSA_style key. */ > - rsa = EVP_PKEY_get1_RSA(key); > - if (!rsa) { > - rsa_err("Couldn't convert to a RSA style key"); > - ret = -EINVAL; > - goto err_rsa; > - } > - > - EVP_PKEY_free(key); > - *rsap = rsa; > - > return 0; > - > -err_rsa: > - EVP_PKEY_free(key); > - return ret; > } > > /* > @@ -191,15 +160,23 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) > /* > * rsa_get_params(): - Get the important parameters of an RSA public key > */ > -static int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, > +static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, > BIGNUM **modulusp, BIGNUM **r_squaredp) > { > + RSA *rsa; > BIGNUM *big1, *big2, *big32, *big2_32; > BIGNUM *n, *r, *r_squared, *tmp; > const BIGNUM *key_n; > BN_CTX *bn_ctx = BN_CTX_new(); > int ret = 0; > > + /* Convert to a RSA_style key. */ > + rsa = EVP_PKEY_get1_RSA(key); > + if (!rsa) { > + rsa_err("Couldn't convert to a RSA style key"); > + return -EINVAL; > + } > + > /* Initialize BIGNUMs */ > big1 = BN_new(); > big2 = BN_new(); > @@ -215,10 +192,10 @@ static int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, > return -ENOMEM; > } > > - if (0 != rsa_get_exponent(key, exponent)) > + if (0 != rsa_get_exponent(rsa, exponent)) > ret = -1; > > - RSA_get0_key(key, &key_n, NULL, NULL); > + RSA_get0_key(rsa, &key_n, NULL, NULL); > if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || > !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) > ret = -1; > @@ -384,7 +361,7 @@ static int gen_key(const char *keyname, const char *path) > uint32_t n0_inv; > int ret; > int bits; > - RSA *rsa; > + EVP_PKEY *key; > ENGINE *e = NULL; > char *tmp, *key_name_c; > > @@ -410,16 +387,16 @@ static int gen_key(const char *keyname, const char *path) > ret = rsa_engine_init(&e); > if (ret) > exit(1); > - ret = rsa_engine_get_pub_key(path, e, &rsa); > + ret = engine_get_pub_key(path, e, &key); > if (ret) > exit(1); > } else { > - ret = rsa_pem_get_pub_key(path, &rsa); > + ret = pem_get_pub_key(path, &key); > if (ret) > exit(1); > } > > - ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared); > + ret = rsa_get_params(key, &exponent, &n0_inv, &modulus, &r_squared); > if (ret) > return ret; > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 05/19] rsatoc: rename rsa_err() to openssl_error() 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (3 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 04/19] rsatoc: pass EVP_PKEY around Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:37 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 06/19] rsatoc: move engine initialization to engine_get_pub_key() Sascha Hauer ` (14 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List There's nothing rsa_err() specific in this function, rename to openssl_error(). Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 462963424a..1d2eb48d08 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -21,7 +21,7 @@ static int dts, standalone; -static int rsa_err(const char *msg) +static int openssl_error(const char *msg) { unsigned long sslErr = ERR_get_error(); @@ -61,7 +61,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) rewind(f); key = PEM_read_PUBKEY(f, NULL, NULL, NULL); if (!key) { - rsa_err("Couldn't read certificate"); + openssl_error("Couldn't read certificate"); ret = -EINVAL; goto err_cert; } @@ -69,7 +69,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) /* Get the public key from the certificate. */ key = X509_get_pubkey(cert); if (!key) { - rsa_err("Couldn't read public key\n"); + openssl_error("Couldn't read public key\n"); ret = -EINVAL; goto err_pubkey; } @@ -103,7 +103,7 @@ static int engine_get_pub_key(const char *key_id, { *key = ENGINE_load_public_key(engine, key_id, NULL, NULL); if (!*key) - return rsa_err("Failure loading public key from engine"); + return openssl_error("Failure loading public key from engine"); return 0; } @@ -173,7 +173,7 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, /* Convert to a RSA_style key. */ rsa = EVP_PKEY_get1_RSA(key); if (!rsa) { - rsa_err("Couldn't convert to a RSA style key"); + openssl_error("Couldn't convert to a RSA style key"); return -EINVAL; } -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 05/19] rsatoc: rename rsa_err() to openssl_error() 2024-08-01 5:57 ` [PATCH v2 05/19] rsatoc: rename rsa_err() to openssl_error() Sascha Hauer @ 2024-08-05 9:37 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:37 UTC (permalink / raw) To: Sascha Hauer, Barebox List Hello Sascha, On 01.08.24 07:57, Sascha Hauer wrote: > There's nothing rsa_err() specific in this function, rename to > openssl_error(). > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> Just one nit below, which can follow separately though. > --- > scripts/rsatoc.c | 10 +++++----- > 1 file changed, 5 insertions(+), 5 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index 462963424a..1d2eb48d08 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -21,7 +21,7 @@ > > static int dts, standalone; > > -static int rsa_err(const char *msg) > +static int openssl_error(const char *msg) > { > unsigned long sslErr = ERR_get_error(); > > @@ -61,7 +61,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > rewind(f); > key = PEM_read_PUBKEY(f, NULL, NULL, NULL); > if (!key) { > - rsa_err("Couldn't read certificate"); > + openssl_error("Couldn't read certificate"); > ret = -EINVAL; > goto err_cert; > } > @@ -69,7 +69,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > /* Get the public key from the certificate. */ > key = X509_get_pubkey(cert); > if (!key) { > - rsa_err("Couldn't read public key\n"); > + openssl_error("Couldn't read public key\n"); No fault of this patch, but this trailing line feed should be dropped, so the error message doesn't span two lines. > ret = -EINVAL; > goto err_pubkey; > } > @@ -103,7 +103,7 @@ static int engine_get_pub_key(const char *key_id, > { > *key = ENGINE_load_public_key(engine, key_id, NULL, NULL); > if (!*key) > - return rsa_err("Failure loading public key from engine"); > + return openssl_error("Failure loading public key from engine"); > > return 0; > } > @@ -173,7 +173,7 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, > /* Convert to a RSA_style key. */ > rsa = EVP_PKEY_get1_RSA(key); > if (!rsa) { > - rsa_err("Couldn't convert to a RSA style key"); > + openssl_error("Couldn't convert to a RSA style key"); > return -EINVAL; > } > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 06/19] rsatoc: move engine initialization to engine_get_pub_key() 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (4 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 05/19] rsatoc: rename rsa_err() to openssl_error() Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:47 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 07/19] rsatoc: cleanup error handling Sascha Hauer ` (13 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List The openssl engine is only used in engine_get_pub_key(), so initialize is there instead of in the caller. This is done in preparation of replacing the deprecated engine code with a provider. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 107 ++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 1d2eb48d08..0faf41bca2 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -89,19 +89,68 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) return ret; } +static int engine_init(ENGINE **pe) +{ + ENGINE *e; + int ret; + const char *key_pass = getenv("KBUILD_SIGN_PIN"); + + ENGINE_load_builtin_engines(); + + e = ENGINE_by_id("pkcs11"); + if (!e) { + fprintf(stderr, "Engine isn't available\n"); + ret = -1; + goto err_engine_by_id; + } + + if (!ENGINE_init(e)) { + fprintf(stderr, "Couldn't initialize engine\n"); + ret = -1; + goto err_engine_init; + } + + if (key_pass) { + if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) { + fprintf(stderr, "Cannot set PKCS#11 PIN\n"); + goto err_set_rsa; + } + } + + *pe = e; + + return 0; + +err_set_rsa: + ENGINE_finish(e); +err_engine_init: + ENGINE_free(e); +err_engine_by_id: +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL) + ENGINE_cleanup(); +#endif + return ret; +} + /** * engine_get_pub_key() - read a public key from given engine * * @keydir: Key prefix * @name Name of key - * @engine Engine to use * @key Returns key object, or NULL on failure * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) */ -static int engine_get_pub_key(const char *key_id, - ENGINE *engine, EVP_PKEY **key) +static int engine_get_pub_key(const char *key_id, EVP_PKEY **key) { - *key = ENGINE_load_public_key(engine, key_id, NULL, NULL); + ENGINE *e; + int ret; + + ret = engine_init(&e); + if (ret) + return ret; + + *key = ENGINE_load_public_key(e, key_id, NULL, NULL); if (!*key) return openssl_error("Failure loading public key from engine"); @@ -238,50 +287,6 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, return ret; } -static int rsa_engine_init(ENGINE **pe) -{ - ENGINE *e; - int ret; - const char *key_pass = getenv("KBUILD_SIGN_PIN"); - - ENGINE_load_builtin_engines(); - - e = ENGINE_by_id("pkcs11"); - if (!e) { - fprintf(stderr, "Engine isn't available\n"); - ret = -1; - goto err_engine_by_id; - } - - if (!ENGINE_init(e)) { - fprintf(stderr, "Couldn't initialize engine\n"); - ret = -1; - goto err_engine_init; - } - - if (key_pass) { - if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) { - fprintf(stderr, "Cannot set PKCS#11 PIN\n"); - goto err_set_rsa; - } - } - - *pe = e; - - return 0; - -err_set_rsa: - ENGINE_finish(e); -err_engine_init: - ENGINE_free(e); -err_engine_by_id: -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL) - ENGINE_cleanup(); -#endif - return ret; -} - static FILE *outfilep; static int print_bignum(BIGNUM *num, int num_bits) @@ -362,7 +367,6 @@ static int gen_key(const char *keyname, const char *path) int ret; int bits; EVP_PKEY *key; - ENGINE *e = NULL; char *tmp, *key_name_c; tmp = key_name_c = strdup(keyname); @@ -384,10 +388,7 @@ static int gen_key(const char *keyname, const char *path) } if (!strncmp(path, "pkcs11:", 7)) { - ret = rsa_engine_init(&e); - if (ret) - exit(1); - ret = engine_get_pub_key(path, e, &key); + ret = engine_get_pub_key(path, &key); if (ret) exit(1); } else { -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 06/19] rsatoc: move engine initialization to engine_get_pub_key() 2024-08-01 5:57 ` [PATCH v2 06/19] rsatoc: move engine initialization to engine_get_pub_key() Sascha Hauer @ 2024-08-05 9:47 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:47 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > The openssl engine is only used in engine_get_pub_key(), so initialize > is there instead of in the caller. This is done in preparation of > replacing the deprecated engine code with a provider. This commit message is outdated. > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> With the message reworded: Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 107 ++++++++++++++++++++++++----------------------- > 1 file changed, 54 insertions(+), 53 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index 1d2eb48d08..0faf41bca2 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -89,19 +89,68 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > return ret; > } > > +static int engine_init(ENGINE **pe) > +{ > + ENGINE *e; > + int ret; > + const char *key_pass = getenv("KBUILD_SIGN_PIN"); > + > + ENGINE_load_builtin_engines(); > + > + e = ENGINE_by_id("pkcs11"); > + if (!e) { > + fprintf(stderr, "Engine isn't available\n"); > + ret = -1; > + goto err_engine_by_id; > + } > + > + if (!ENGINE_init(e)) { > + fprintf(stderr, "Couldn't initialize engine\n"); > + ret = -1; > + goto err_engine_init; > + } > + > + if (key_pass) { > + if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) { > + fprintf(stderr, "Cannot set PKCS#11 PIN\n"); > + goto err_set_rsa; > + } > + } > + > + *pe = e; > + > + return 0; > + > +err_set_rsa: > + ENGINE_finish(e); > +err_engine_init: > + ENGINE_free(e); > +err_engine_by_id: > +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ > + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL) > + ENGINE_cleanup(); > +#endif > + return ret; > +} > + > /** > * engine_get_pub_key() - read a public key from given engine > * > * @keydir: Key prefix > * @name Name of key > - * @engine Engine to use > * @key Returns key object, or NULL on failure > * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) > */ > -static int engine_get_pub_key(const char *key_id, > - ENGINE *engine, EVP_PKEY **key) > +static int engine_get_pub_key(const char *key_id, EVP_PKEY **key) > { > - *key = ENGINE_load_public_key(engine, key_id, NULL, NULL); > + ENGINE *e; > + int ret; > + > + ret = engine_init(&e); > + if (ret) > + return ret; > + > + *key = ENGINE_load_public_key(e, key_id, NULL, NULL); > if (!*key) > return openssl_error("Failure loading public key from engine"); > > @@ -238,50 +287,6 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, > return ret; > } > > -static int rsa_engine_init(ENGINE **pe) > -{ > - ENGINE *e; > - int ret; > - const char *key_pass = getenv("KBUILD_SIGN_PIN"); > - > - ENGINE_load_builtin_engines(); > - > - e = ENGINE_by_id("pkcs11"); > - if (!e) { > - fprintf(stderr, "Engine isn't available\n"); > - ret = -1; > - goto err_engine_by_id; > - } > - > - if (!ENGINE_init(e)) { > - fprintf(stderr, "Couldn't initialize engine\n"); > - ret = -1; > - goto err_engine_init; > - } > - > - if (key_pass) { > - if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) { > - fprintf(stderr, "Cannot set PKCS#11 PIN\n"); > - goto err_set_rsa; > - } > - } > - > - *pe = e; > - > - return 0; > - > -err_set_rsa: > - ENGINE_finish(e); > -err_engine_init: > - ENGINE_free(e); > -err_engine_by_id: > -#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ > - (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL) > - ENGINE_cleanup(); > -#endif > - return ret; > -} > - > static FILE *outfilep; > > static int print_bignum(BIGNUM *num, int num_bits) > @@ -362,7 +367,6 @@ static int gen_key(const char *keyname, const char *path) > int ret; > int bits; > EVP_PKEY *key; > - ENGINE *e = NULL; > char *tmp, *key_name_c; > > tmp = key_name_c = strdup(keyname); > @@ -384,10 +388,7 @@ static int gen_key(const char *keyname, const char *path) > } > > if (!strncmp(path, "pkcs11:", 7)) { > - ret = rsa_engine_init(&e); > - if (ret) > - exit(1); > - ret = engine_get_pub_key(path, e, &key); > + ret = engine_get_pub_key(path, &key); > if (ret) > exit(1); > } else { -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 07/19] rsatoc: cleanup error handling 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (5 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 06/19] rsatoc: move engine initialization to engine_get_pub_key() Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:54 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 08/19] rsatoc: remove unnecessary error check Sascha Hauer ` (12 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List - In case of an error bail out immediately instead of continuing and just return an error at the end - explicitly set 'ret' right before going to the cleanup label which makes the code more readable Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 58 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 0faf41bca2..22f0318298 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -167,15 +167,16 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) const BIGNUM *key_e; uint64_t te; - ret = -EINVAL; bn_te = NULL; if (!e) goto cleanup; RSA_get0_key(key, NULL, &key_e, NULL); - if (BN_num_bits(key_e) > 64) + if (BN_num_bits(key_e) > 64) { + ret = -EINVAL; goto cleanup; + } *e = BN_get_word(key_e); @@ -185,14 +186,20 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) } bn_te = BN_dup(key_e); - if (!bn_te) + if (!bn_te) { + ret = -EINVAL; goto cleanup; + } - if (!BN_rshift(bn_te, bn_te, 32)) + if (!BN_rshift(bn_te, bn_te, 32)) { + ret = -EINVAL; goto cleanup; + } - if (!BN_mask_bits(bn_te, 32)) + if (!BN_mask_bits(bn_te, 32)) { + ret = -EINVAL; goto cleanup; + } te = BN_get_word(bn_te); te <<= 32; @@ -217,7 +224,7 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, BIGNUM *n, *r, *r_squared, *tmp; const BIGNUM *key_n; BN_CTX *bn_ctx = BN_CTX_new(); - int ret = 0; + int ret; /* Convert to a RSA_style key. */ rsa = EVP_PKEY_get1_RSA(key); @@ -241,38 +248,53 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, return -ENOMEM; } - if (0 != rsa_get_exponent(rsa, exponent)) - ret = -1; + ret = rsa_get_exponent(rsa, exponent); + if (ret) + goto cleanup; RSA_get0_key(rsa, &key_n, NULL, NULL); if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || - !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) - ret = -1; + !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) { + ret = -EINVAL; + goto cleanup; + } /* big2_32 = 2^32 */ - if (!BN_exp(big2_32, big2, big32, bn_ctx)) - ret = -1; + if (!BN_exp(big2_32, big2, big32, bn_ctx)) { + ret = -EINVAL; + goto cleanup; + } /* Calculate n0_inv = -1 / n[0] mod 2^32 */ if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) || - !BN_sub(tmp, big2_32, tmp)) - ret = -1; + !BN_sub(tmp, big2_32, tmp)) { + ret = -EINVAL; + goto cleanup; + } + *n0_invp = BN_get_word(tmp); /* Calculate R = 2^(# of key bits) */ if (!BN_set_word(tmp, BN_num_bits(n)) || - !BN_exp(r, big2, tmp, bn_ctx)) - ret = -1; + !BN_exp(r, big2, tmp, bn_ctx)) { + ret = -EINVAL; + goto cleanup; + } /* Calculate r_squared = R^2 mod n */ if (!BN_copy(r_squared, r) || !BN_mul(tmp, r_squared, r, bn_ctx) || - !BN_mod(r_squared, tmp, n, bn_ctx)) - ret = -1; + !BN_mod(r_squared, tmp, n, bn_ctx)) { + ret = -EINVAL; + goto cleanup; + } *modulusp = n; *r_squaredp = r_squared; + ret = 0; + +cleanup: BN_free(big1); BN_free(big2); BN_free(big32); -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 07/19] rsatoc: cleanup error handling 2024-08-01 5:57 ` [PATCH v2 07/19] rsatoc: cleanup error handling Sascha Hauer @ 2024-08-05 9:54 ` Ahmad Fatoum 2024-08-05 10:07 ` Sascha Hauer 0 siblings, 1 reply; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:54 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > - In case of an error bail out immediately instead of continuing and > just return an error at the end > - explicitly set 'ret' right before going to the cleanup label which > makes the code more readable > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > scripts/rsatoc.c | 58 +++++++++++++++++++++++++++++++++--------------- > 1 file changed, 40 insertions(+), 18 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index 0faf41bca2..22f0318298 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -167,15 +167,16 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) > const BIGNUM *key_e; > uint64_t te; > > - ret = -EINVAL; > bn_te = NULL; > > if (!e) > goto cleanup; Won't ret be undefined here? Also the return value is ultimately used only for an error message, gen_key's error is not propagated, but it should result in the utility aborting with an error code. Cheers, Ahmad -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 07/19] rsatoc: cleanup error handling 2024-08-05 9:54 ` Ahmad Fatoum @ 2024-08-05 10:07 ` Sascha Hauer 0 siblings, 0 replies; 45+ messages in thread From: Sascha Hauer @ 2024-08-05 10:07 UTC (permalink / raw) To: Ahmad Fatoum; +Cc: Barebox List On Mon, Aug 05, 2024 at 11:54:56AM +0200, Ahmad Fatoum wrote: > On 01.08.24 07:57, Sascha Hauer wrote: > > - In case of an error bail out immediately instead of continuing and > > just return an error at the end > > - explicitly set 'ret' right before going to the cleanup label which > > makes the code more readable > > > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > > --- > > scripts/rsatoc.c | 58 +++++++++++++++++++++++++++++++++--------------- > > 1 file changed, 40 insertions(+), 18 deletions(-) > > > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > > index 0faf41bca2..22f0318298 100644 > > --- a/scripts/rsatoc.c > > +++ b/scripts/rsatoc.c > > @@ -167,15 +167,16 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) > > const BIGNUM *key_e; > > uint64_t te; > > > > - ret = -EINVAL; > > bn_te = NULL; > > > > if (!e) > > goto cleanup; > > Won't ret be undefined here? Indeed. This check is removed anyway in the next patch, so doesn't matter much. I'll just swap this one with the next patch. > > Also the return value is ultimately used only for an error message, > gen_key's error is not propagated, but it should result in the utility > aborting with an error code. Fixed further down this series, but you noticed yourself already. Sascha -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 08/19] rsatoc: remove unnecessary error check 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (6 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 07/19] rsatoc: cleanup error handling Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 9:56 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params Sascha Hauer ` (11 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List In rsa_get_exponent() 'e' will always be a non NULL argument, no need to check for it. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 22f0318298..afef6212d0 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -163,15 +163,10 @@ static int engine_get_pub_key(const char *key_id, EVP_PKEY **key) static int rsa_get_exponent(RSA *key, uint64_t *e) { int ret; - BIGNUM *bn_te; + BIGNUM *bn_te = NULL; const BIGNUM *key_e; uint64_t te; - bn_te = NULL; - - if (!e) - goto cleanup; - RSA_get0_key(key, NULL, &key_e, NULL); if (BN_num_bits(key_e) > 64) { ret = -EINVAL; -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 08/19] rsatoc: remove unnecessary error check 2024-08-01 5:57 ` [PATCH v2 08/19] rsatoc: remove unnecessary error check Sascha Hauer @ 2024-08-05 9:56 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 9:56 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > In rsa_get_exponent() 'e' will always be a non NULL argument, no need to > check for it. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 7 +------ > 1 file changed, 1 insertion(+), 6 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index 22f0318298..afef6212d0 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -163,15 +163,10 @@ static int engine_get_pub_key(const char *key_id, EVP_PKEY **key) > static int rsa_get_exponent(RSA *key, uint64_t *e) > { > int ret; > - BIGNUM *bn_te; > + BIGNUM *bn_te = NULL; > const BIGNUM *key_e; > uint64_t te; > > - bn_te = NULL; > - > - if (!e) > - goto cleanup; > - > RSA_get0_key(key, NULL, &key_e, NULL); > if (BN_num_bits(key_e) > 64) { > ret = -EINVAL; -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (7 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 08/19] rsatoc: remove unnecessary error check Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:02 ` Ahmad Fatoum 2024-08-05 10:29 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 10/19] rsatoc: check error value of gen_key() Sascha Hauer ` (10 subsequent siblings) 19 siblings, 2 replies; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List EVP_PKEY_get1_RSA() and RSA_get0_key() are deprecated. Use EVP_PKEY_get_bn_param() instead. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index afef6212d0..c7bc4ba843 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -18,6 +18,8 @@ #include <openssl/ssl.h> #include <openssl/evp.h> #include <openssl/engine.h> +#include <openssl/provider.h> +#include <openssl/core_names.h> static int dts, standalone; @@ -160,14 +162,17 @@ static int engine_get_pub_key(const char *key_id, EVP_PKEY **key) /* * rsa_get_exponent(): - Get the public exponent from an RSA key */ -static int rsa_get_exponent(RSA *key, uint64_t *e) +static int rsa_get_exponent(EVP_PKEY *key, uint64_t *e) { int ret; BIGNUM *bn_te = NULL; - const BIGNUM *key_e; + BIGNUM *key_e = NULL; uint64_t te; - RSA_get0_key(key, NULL, &key_e, NULL); + ret = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_E, &key_e); + if (!ret) + return -EINVAL; + if (BN_num_bits(key_e) > 64) { ret = -EINVAL; goto cleanup; @@ -204,6 +209,7 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) cleanup: if (bn_te) BN_free(bn_te); + BN_free(key_e); return ret; } @@ -214,20 +220,12 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, BIGNUM **modulusp, BIGNUM **r_squaredp) { - RSA *rsa; BIGNUM *big1, *big2, *big32, *big2_32; BIGNUM *n, *r, *r_squared, *tmp; - const BIGNUM *key_n; + BIGNUM *key_n = NULL; BN_CTX *bn_ctx = BN_CTX_new(); int ret; - /* Convert to a RSA_style key. */ - rsa = EVP_PKEY_get1_RSA(key); - if (!rsa) { - openssl_error("Couldn't convert to a RSA style key"); - return -EINVAL; - } - /* Initialize BIGNUMs */ big1 = BN_new(); big2 = BN_new(); @@ -243,11 +241,14 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, return -ENOMEM; } - ret = rsa_get_exponent(rsa, exponent); + ret = rsa_get_exponent(key, exponent); if (ret) goto cleanup; - RSA_get0_key(rsa, &key_n, NULL, NULL); + ret = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_N, &key_n); + if (!ret) + return -EINVAL; + if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) { ret = -EINVAL; -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params 2024-08-01 5:57 ` [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params Sascha Hauer @ 2024-08-05 10:02 ` Ahmad Fatoum 2024-08-05 10:29 ` Ahmad Fatoum 1 sibling, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:02 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > EVP_PKEY_get1_RSA() and RSA_get0_key() are deprecated. Use > EVP_PKEY_get_bn_param() instead. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 29 +++++++++++++++-------------- > 1 file changed, 15 insertions(+), 14 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index afef6212d0..c7bc4ba843 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -18,6 +18,8 @@ > #include <openssl/ssl.h> > #include <openssl/evp.h> > #include <openssl/engine.h> > +#include <openssl/provider.h> > +#include <openssl/core_names.h> > > static int dts, standalone; > > @@ -160,14 +162,17 @@ static int engine_get_pub_key(const char *key_id, EVP_PKEY **key) > /* > * rsa_get_exponent(): - Get the public exponent from an RSA key > */ > -static int rsa_get_exponent(RSA *key, uint64_t *e) > +static int rsa_get_exponent(EVP_PKEY *key, uint64_t *e) > { > int ret; > BIGNUM *bn_te = NULL; > - const BIGNUM *key_e; > + BIGNUM *key_e = NULL; > uint64_t te; > > - RSA_get0_key(key, NULL, &key_e, NULL); > + ret = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_E, &key_e); > + if (!ret) > + return -EINVAL; > + > if (BN_num_bits(key_e) > 64) { > ret = -EINVAL; > goto cleanup; > @@ -204,6 +209,7 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) > cleanup: > if (bn_te) > BN_free(bn_te); > + BN_free(key_e); > > return ret; > } > @@ -214,20 +220,12 @@ static int rsa_get_exponent(RSA *key, uint64_t *e) > static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, > BIGNUM **modulusp, BIGNUM **r_squaredp) > { > - RSA *rsa; > BIGNUM *big1, *big2, *big32, *big2_32; > BIGNUM *n, *r, *r_squared, *tmp; > - const BIGNUM *key_n; > + BIGNUM *key_n = NULL; > BN_CTX *bn_ctx = BN_CTX_new(); > int ret; > > - /* Convert to a RSA_style key. */ > - rsa = EVP_PKEY_get1_RSA(key); > - if (!rsa) { > - openssl_error("Couldn't convert to a RSA style key"); > - return -EINVAL; > - } > - > /* Initialize BIGNUMs */ > big1 = BN_new(); > big2 = BN_new(); > @@ -243,11 +241,14 @@ static int rsa_get_params(EVP_PKEY *key, uint64_t *exponent, uint32_t *n0_invp, > return -ENOMEM; > } > > - ret = rsa_get_exponent(rsa, exponent); > + ret = rsa_get_exponent(key, exponent); > if (ret) > goto cleanup; > > - RSA_get0_key(rsa, &key_n, NULL, NULL); > + ret = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_RSA_N, &key_n); > + if (!ret) > + return -EINVAL; > + > if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) || > !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) { > ret = -EINVAL; -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params 2024-08-01 5:57 ` [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params Sascha Hauer 2024-08-05 10:02 ` Ahmad Fatoum @ 2024-08-05 10:29 ` Ahmad Fatoum 1 sibling, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:29 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > EVP_PKEY_get1_RSA() and RSA_get0_key() are deprecated. Use > EVP_PKEY_get_bn_param() instead. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > scripts/rsatoc.c | 29 +++++++++++++++-------------- > 1 file changed, 15 insertions(+), 14 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index afef6212d0..c7bc4ba843 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -18,6 +18,8 @@ > #include <openssl/ssl.h> > #include <openssl/evp.h> > #include <openssl/engine.h> > +#include <openssl/provider.h> This is unused and might break compatibility with older OpenSSL versions? Please drop, until we add provider support for real. -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 10/19] rsatoc: check error value of gen_key() 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (8 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:03 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 11/19] rsatoc: rename to keytoc Sascha Hauer ` (9 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List exit with an error in case gen_key() fails, otherwise errors go through unnoticed. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/rsatoc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index c7bc4ba843..27f0afe61f 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -471,7 +471,7 @@ static int gen_key(const char *keyname, const char *path) int main(int argc, char *argv[]) { char *path, *keyname; - int i, opt; + int i, opt, ret; char *outfile = NULL; outfilep = stdout; @@ -542,7 +542,9 @@ int main(int argc, char *argv[]) } } - gen_key(keyname, path); + ret = gen_key(keyname, path); + if (ret) + exit(1); } if (dts) { -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 10/19] rsatoc: check error value of gen_key() 2024-08-01 5:57 ` [PATCH v2 10/19] rsatoc: check error value of gen_key() Sascha Hauer @ 2024-08-05 10:03 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:03 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > exit with an error in case gen_key() fails, otherwise errors go through > unnoticed. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Ah, nice that you caught this. Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/rsatoc.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c > index c7bc4ba843..27f0afe61f 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/rsatoc.c > @@ -471,7 +471,7 @@ static int gen_key(const char *keyname, const char *path) > int main(int argc, char *argv[]) > { > char *path, *keyname; > - int i, opt; > + int i, opt, ret; > char *outfile = NULL; > > outfilep = stdout; > @@ -542,7 +542,9 @@ int main(int argc, char *argv[]) > } > } > > - gen_key(keyname, path); > + ret = gen_key(keyname, path); > + if (ret) > + exit(1); > } > > if (dts) { -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 11/19] rsatoc: rename to keytoc 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (9 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 10/19] rsatoc: check error value of gen_key() Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:05 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 12/19] keytoc: add ecdsa support Sascha Hauer ` (8 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List The rsatoc tool will be extended to also handle ecdsa keys, so change 'rsa' to a more generic name 'key'. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- crypto/Kconfig | 2 +- crypto/Makefile | 2 +- scripts/.gitignore | 2 +- scripts/Kconfig | 4 ++-- scripts/Makefile | 6 +++--- scripts/Makefile.lib | 12 ++++++------ scripts/{rsatoc.c => keytoc.c} | 4 ++-- test/self/Makefile | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) rename scripts/{rsatoc.c => keytoc.c} (99%) diff --git a/crypto/Kconfig b/crypto/Kconfig index d1360a2101..78b499f646 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -121,7 +121,7 @@ config CRYPTO_RSA config CRYPTO_RSA_BUILTIN_KEYS bool default y if CRYPTO_RSA_KEY != "" - select RSATOC + select KEYTOC config CRYPTO_RSA_KEY depends on CRYPTO_RSA diff --git a/crypto/Makefile b/crypto/Makefile index cf041dd6b3..e84360a8c7 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -34,5 +34,5 @@ RSA_DEP := $(CONFIG_CRYPTO_RSA_KEY) endif $(obj)/rsa-keys.h: $(RSA_DEP) FORCE - $(call cmd,rsa_keys,$(CONFIG_CRYPTO_RSA_KEY_NAME_HINT):$(if $(RSA_DEP),$<,$(CONFIG_CRYPTO_RSA_KEY))) + $(call cmd,public_keys,$(CONFIG_CRYPTO_RSA_KEY_NAME_HINT):$(if $(RSA_DEP),$<,$(CONFIG_CRYPTO_RSA_KEY))) endif diff --git a/scripts/.gitignore b/scripts/.gitignore index 8c653d184f..6ee81e8998 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -33,7 +33,7 @@ rk-usb-loader rk-usb-loader-target rkimage mips-relocs -rsatoc +keytoc stm32image mvebuimg prelink-riscv diff --git a/scripts/Kconfig b/scripts/Kconfig index 4034f020d0..62bf0298ec 100644 --- a/scripts/Kconfig +++ b/scripts/Kconfig @@ -110,10 +110,10 @@ config QOICONV help This enable converting png to qoi images to generate boot logo. -config RSATOC +config KEYTOC bool "RSA to C converter" if COMPILE_HOST_TOOLS help - This utility converts RSA keys in PEM format to either C or + This utility converts public keys in PEM format to either C or device tree snippets. This requires OpenSSL on the build host and will be selected by the build system if required. diff --git a/scripts/Makefile b/scripts/Makefile index 20da6fc5e7..a780f05bd9 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -10,9 +10,9 @@ hostprogs-always-y += bareboxenv hostprogs-always-y += bareboxcrc32 hostprogs-always-y += kernel-install hostprogs-always-$(CONFIG_QOICONV) += qoiconv -hostprogs-always-$(CONFIG_RSATOC) += rsatoc -HOSTCFLAGS_rsatoc.o = `$(PKG_CONFIG) --cflags openssl` -HOSTLDLIBS_rsatoc = `$(PKG_CONFIG) --libs openssl` +hostprogs-always-$(CONFIG_KEYTOC) += keytoc +HOSTCFLAGS_keytoc.o = `$(PKG_CONFIG) --cflags openssl` +HOSTLDLIBS_keytoc = `$(PKG_CONFIG) --libs openssl` hostprogs-always-$(CONFIG_IMD) += bareboximd hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms hostprogs-always-$(CONFIG_MIPS) += mips-relocs diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 6b1f0ccbc0..1881e3c139 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -604,17 +604,17 @@ quiet_cmd_stm32_image = STM32-IMG $@ quiet_cmd_b64dec = B64DEC $@ cmd_b64dec = base64 -d $< > $@ -# rsa_keys +# public_keys # --------------------------------------------------------------------------- # Build a header file containing a rsa public key. # # The keys can change without the build system noticing, so we always -# have to call rsatoc. To avoid unnecessary rebuilds of barebox compare -# its output to the last rsatoc output. Only if it differs overwrite the +# have to call keytoc. To avoid unnecessary rebuilds of barebox compare +# its output to the last keytoc output. Only if it differs overwrite the # target file. -quiet_cmd_rsa_keys = RSAKEY $@ -cmd_rsa_keys = \ - $(objtree)/scripts/rsatoc -o $@.tmp "$(2)" $(3) && \ +quiet_cmd_public_keys = KEY $@ +cmd_public_keys = \ + $(objtree)/scripts/keytoc -o $@.tmp "$(2)" $(3) && \ if cmp -s $@.tmp $@; then \ rm $@.tmp; \ else \ diff --git a/scripts/rsatoc.c b/scripts/keytoc.c similarity index 99% rename from scripts/rsatoc.c rename to scripts/keytoc.c index 27f0afe61f..891425cecc 100644 --- a/scripts/rsatoc.c +++ b/scripts/keytoc.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-OpenSSL-exception /* - * rsatoc - utility to convert an RSA key to a C struct + * keytoc - utility to convert a public key to a C struct * - * This tool converts an RSA key given as file or PKCS#11 + * This tool converts an public key given as file or PKCS#11 * URI to a C struct suitable to compile with barebox. */ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" diff --git a/test/self/Makefile b/test/self/Makefile index fbc1867254..6390c4afd4 100644 --- a/test/self/Makefile +++ b/test/self/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_SELFTEST_IDR) += idr.o ifdef REGENERATE_RSATOC $(obj)/jwt_test.pem.c_shipped: $(src)/jwt_test.pem FORCE - $(call if_changed,rsa_keys,$(basename $(target-stem)):$<,-s) + $(call if_changed,public_keys,$(basename $(target-stem)):$<,-s) endif -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 11/19] rsatoc: rename to keytoc 2024-08-01 5:57 ` [PATCH v2 11/19] rsatoc: rename to keytoc Sascha Hauer @ 2024-08-05 10:05 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:05 UTC (permalink / raw) To: Sascha Hauer, Barebox List Hello Sascha, On 01.08.24 07:57, Sascha Hauer wrote: > The rsatoc tool will be extended to also handle ecdsa keys, so change > 'rsa' to a more generic name 'key'. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > crypto/Kconfig | 2 +- > crypto/Makefile | 2 +- > scripts/.gitignore | 2 +- > scripts/Kconfig | 4 ++-- > scripts/Makefile | 6 +++--- > scripts/Makefile.lib | 12 ++++++------ > scripts/{rsatoc.c => keytoc.c} | 4 ++-- > test/self/Makefile | 2 +- > 8 files changed, 17 insertions(+), 17 deletions(-) > rename scripts/{rsatoc.c => keytoc.c} (99%) > > diff --git a/crypto/Kconfig b/crypto/Kconfig > index d1360a2101..78b499f646 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -121,7 +121,7 @@ config CRYPTO_RSA > config CRYPTO_RSA_BUILTIN_KEYS > bool > default y if CRYPTO_RSA_KEY != "" > - select RSATOC > + select KEYTOC > > config CRYPTO_RSA_KEY > depends on CRYPTO_RSA > diff --git a/crypto/Makefile b/crypto/Makefile > index cf041dd6b3..e84360a8c7 100644 > --- a/crypto/Makefile > +++ b/crypto/Makefile > @@ -34,5 +34,5 @@ RSA_DEP := $(CONFIG_CRYPTO_RSA_KEY) > endif > > $(obj)/rsa-keys.h: $(RSA_DEP) FORCE > - $(call cmd,rsa_keys,$(CONFIG_CRYPTO_RSA_KEY_NAME_HINT):$(if $(RSA_DEP),$<,$(CONFIG_CRYPTO_RSA_KEY))) > + $(call cmd,public_keys,$(CONFIG_CRYPTO_RSA_KEY_NAME_HINT):$(if $(RSA_DEP),$<,$(CONFIG_CRYPTO_RSA_KEY))) > endif > diff --git a/scripts/.gitignore b/scripts/.gitignore > index 8c653d184f..6ee81e8998 100644 > --- a/scripts/.gitignore > +++ b/scripts/.gitignore > @@ -33,7 +33,7 @@ rk-usb-loader > rk-usb-loader-target > rkimage > mips-relocs > -rsatoc > +keytoc > stm32image > mvebuimg > prelink-riscv > diff --git a/scripts/Kconfig b/scripts/Kconfig > index 4034f020d0..62bf0298ec 100644 > --- a/scripts/Kconfig > +++ b/scripts/Kconfig > @@ -110,10 +110,10 @@ config QOICONV > help > This enable converting png to qoi images to generate boot logo. > > -config RSATOC > +config KEYTOC > bool "RSA to C converter" if COMPILE_HOST_TOOLS > help > - This utility converts RSA keys in PEM format to either C or > + This utility converts public keys in PEM format to either C or > device tree snippets. This requires OpenSSL on the build host > and will be selected by the build system if required. > > diff --git a/scripts/Makefile b/scripts/Makefile > index 20da6fc5e7..a780f05bd9 100644 > --- a/scripts/Makefile > +++ b/scripts/Makefile > @@ -10,9 +10,9 @@ hostprogs-always-y += bareboxenv > hostprogs-always-y += bareboxcrc32 > hostprogs-always-y += kernel-install > hostprogs-always-$(CONFIG_QOICONV) += qoiconv > -hostprogs-always-$(CONFIG_RSATOC) += rsatoc > -HOSTCFLAGS_rsatoc.o = `$(PKG_CONFIG) --cflags openssl` > -HOSTLDLIBS_rsatoc = `$(PKG_CONFIG) --libs openssl` > +hostprogs-always-$(CONFIG_KEYTOC) += keytoc > +HOSTCFLAGS_keytoc.o = `$(PKG_CONFIG) --cflags openssl` > +HOSTLDLIBS_keytoc = `$(PKG_CONFIG) --libs openssl` > hostprogs-always-$(CONFIG_IMD) += bareboximd > hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms > hostprogs-always-$(CONFIG_MIPS) += mips-relocs > diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib > index 6b1f0ccbc0..1881e3c139 100644 > --- a/scripts/Makefile.lib > +++ b/scripts/Makefile.lib > @@ -604,17 +604,17 @@ quiet_cmd_stm32_image = STM32-IMG $@ > quiet_cmd_b64dec = B64DEC $@ > cmd_b64dec = base64 -d $< > $@ > > -# rsa_keys > +# public_keys > # --------------------------------------------------------------------------- > # Build a header file containing a rsa public key. > # > # The keys can change without the build system noticing, so we always > -# have to call rsatoc. To avoid unnecessary rebuilds of barebox compare > -# its output to the last rsatoc output. Only if it differs overwrite the > +# have to call keytoc. To avoid unnecessary rebuilds of barebox compare > +# its output to the last keytoc output. Only if it differs overwrite the > # target file. > -quiet_cmd_rsa_keys = RSAKEY $@ > -cmd_rsa_keys = \ > - $(objtree)/scripts/rsatoc -o $@.tmp "$(2)" $(3) && \ > +quiet_cmd_public_keys = KEY $@ > +cmd_public_keys = \ > + $(objtree)/scripts/keytoc -o $@.tmp "$(2)" $(3) && \ > if cmp -s $@.tmp $@; then \ > rm $@.tmp; \ > else \ > diff --git a/scripts/rsatoc.c b/scripts/keytoc.c > similarity index 99% > rename from scripts/rsatoc.c > rename to scripts/keytoc.c > index 27f0afe61f..891425cecc 100644 > --- a/scripts/rsatoc.c > +++ b/scripts/keytoc.c > @@ -1,8 +1,8 @@ > // SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-OpenSSL-exception > /* > - * rsatoc - utility to convert an RSA key to a C struct > + * keytoc - utility to convert a public key to a C struct > * > - * This tool converts an RSA key given as file or PKCS#11 > + * This tool converts an public key given as file or PKCS#11 > * URI to a C struct suitable to compile with barebox. > */ > #pragma GCC diagnostic ignored "-Wdeprecated-declarations" > diff --git a/test/self/Makefile b/test/self/Makefile > index fbc1867254..6390c4afd4 100644 > --- a/test/self/Makefile > +++ b/test/self/Makefile > @@ -22,7 +22,7 @@ obj-$(CONFIG_SELFTEST_IDR) += idr.o > ifdef REGENERATE_RSATOC > > $(obj)/jwt_test.pem.c_shipped: $(src)/jwt_test.pem FORCE > - $(call if_changed,rsa_keys,$(basename $(target-stem)):$<,-s) > + $(call if_changed,public_keys,$(basename $(target-stem)):$<,-s) > > endif > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 12/19] keytoc: add ecdsa support 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (10 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 11/19] rsatoc: rename to keytoc Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 11:04 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 13/19] keytoc: Let openssl_error() take a format string Sascha Hauer ` (7 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List This extends the keytoc utility to also handle ecdsa keys. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/keytoc.c | 191 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 161 insertions(+), 30 deletions(-) diff --git a/scripts/keytoc.c b/scripts/keytoc.c index 891425cecc..0883ca64f7 100644 --- a/scripts/keytoc.c +++ b/scripts/keytoc.c @@ -20,6 +20,8 @@ #include <openssl/engine.h> #include <openssl/provider.h> #include <openssl/core_names.h> +#include <openssl/param_build.h> +#include <openssl/store.h> static int dts, standalone; @@ -377,44 +379,131 @@ static int print_bignum(BIGNUM *num, int num_bits) return 0; } -static int gen_key(const char *keyname, const char *path) +/* + * When imported from a HSM the key doesn't have the EC point parameters, + * only the pubkey itself exists. Exporting the pubkey and creating a new + * pkey from it resolves this. This can likely (hopefully) be improved, but + * I don't have an idea how. + */ +static EVP_PKEY *reimport_key(EVP_PKEY *pkey) { - BIGNUM *modulus, *r_squared; - uint64_t exponent = 0; - uint32_t n0_inv; + char group[128] = {}; + size_t outlen; + OSSL_PARAM *params; + OSSL_PARAM_BLD *param_bld = NULL; + unsigned char pub[128] = {}; + size_t len; + EVP_PKEY *pkey_out = NULL; + EVP_PKEY_CTX *pkey_ctx; int ret; - int bits; - EVP_PKEY *key; - char *tmp, *key_name_c; - tmp = key_name_c = strdup(keyname); + ret = EVP_PKEY_get_utf8_string_param(pkey, "group", group, sizeof(group), &outlen); + if (!ret) + return NULL; - while (*tmp) { - if (*tmp == '-') - *tmp = '_'; - tmp++; - } + ret = EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + pub, sizeof(pub), &len); + if (ret <= 0) + return NULL; - if (!strncmp(path, "__ENV__", 7)) { - const char *var = getenv(path + 7); - if (!var) { - fprintf(stderr, - "environment variable \"%s\" is empty\n", path + 7); - exit(1); - } - path = var; - } + param_bld = OSSL_PARAM_BLD_new(); + if (!param_bld) + return NULL; - if (!strncmp(path, "pkcs11:", 7)) { - ret = engine_get_pub_key(path, &key); - if (ret) - exit(1); + ret = OSSL_PARAM_BLD_push_utf8_string(param_bld, "group", group, 0); + if (ret <= 0) + return NULL; + + ret = OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pub, len); + if (ret <= 0) + return NULL; + + params = OSSL_PARAM_BLD_to_param(param_bld); + if (!params) + return NULL; + + pkey_ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); + if (!pkey_ctx) + return NULL; + + ret = EVP_PKEY_fromdata_init(pkey_ctx); + if (ret <= 0) + return NULL; + + ret = EVP_PKEY_fromdata(pkey_ctx, &pkey_out, EVP_PKEY_PUBLIC_KEY, params); + if (ret <= 0) + return NULL; + + return pkey_out; +} + +static int gen_key_ecdsa(EVP_PKEY *key, const char *key_name, const char *key_name_c) +{ + char group[128]; + size_t outlen; + int ret, bits; + BIGNUM *key_x = NULL, *key_y = NULL; + + key = reimport_key(key); + if (!key) + return -EINVAL; + + ret = EVP_PKEY_get_int_param(key, "bits", &bits); + if (!ret) + return -EINVAL; + ret = EVP_PKEY_get_utf8_string_param(key, "group", group, sizeof(group), &outlen); + if (!ret) + return -EINVAL; + + ret = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_EC_PUB_X, &key_x); + if (!ret) + return -EINVAL; + + ret = EVP_PKEY_get_bn_param(key, OSSL_PKEY_PARAM_EC_PUB_Y, &key_y); + if (!ret) + return -EINVAL; + + if (dts) { + fprintf(outfilep, "\t\tkey-%s {\n", key_name_c); + fprintf(outfilep, "\t\t\tecdsa,x-point = <"); + print_bignum(key_x, bits); + fprintf(outfilep, ">;\n"); + fprintf(outfilep, "\t\t\tecdsa,y-point = <"); + print_bignum(key_y, bits); + fprintf(outfilep, ">;\n"); + fprintf(outfilep, "\t\t\tecdsa,curve = \"%s\";\n", group); + fprintf(outfilep, "\t\t};\n"); } else { - ret = pem_get_pub_key(path, &key); - if (ret) - exit(1); + fprintf(outfilep, "\nstatic uint32_t %s_x[] = {", key_name_c); + print_bignum(key_x, bits); + fprintf(outfilep, "\n};\n\n"); + + fprintf(outfilep, "static uint32_t %s_y[] = {", key_name_c); + print_bignum(key_y, bits); + fprintf(outfilep, "\n};\n\n"); + + fprintf(outfilep, "static struct ecdsa_public_key %s = {\n", key_name_c); + + fprintf(outfilep, "\t.curve_name = \"%s\",\n", group); + fprintf(outfilep, "\t.x = %s_x,\n", key_name_c); + fprintf(outfilep, "\t.y = %s_y,\n", key_name_c); + fprintf(outfilep, "};\n"); + if (!standalone) + fprintf(outfilep, "\nstruct ecdsa_public_key *%s_ecdsa_p __attribute__((section(\".ecdsa_keys.rodata.%s\"))) = &%s;\n", + key_name_c, key_name_c, key_name_c); } + return 0; +} + +static int gen_key_rsa(EVP_PKEY *key, const char *key_name, const char *key_name_c) +{ + BIGNUM *modulus, *r_squared; + uint64_t exponent = 0; + uint32_t n0_inv; + int bits; + int ret; + ret = rsa_get_params(key, &exponent, &n0_inv, &modulus, &r_squared); if (ret) return ret; @@ -457,7 +546,7 @@ static int gen_key(const char *keyname, const char *path) fprintf(outfilep, "\t.modulus = %s_modulus,\n", key_name_c); fprintf(outfilep, "\t.rr = %s_rr,\n", key_name_c); fprintf(outfilep, "\t.exponent = 0x%0lx,\n", exponent); - fprintf(outfilep, "\t.key_name_hint = \"%s\",\n", keyname); + fprintf(outfilep, "\t.key_name_hint = \"%s\",\n", key_name); fprintf(outfilep, "};\n"); if (!standalone) @@ -468,6 +557,47 @@ static int gen_key(const char *keyname, const char *path) return 0; } +static int gen_key(const char *keyname, const char *path) +{ + int ret; + EVP_PKEY *key; + char *tmp, *key_name_c; + + tmp = key_name_c = strdup(keyname); + + while (*tmp) { + if (*tmp == '-') + *tmp = '_'; + tmp++; + } + + if (!strncmp(path, "__ENV__", 7)) { + const char *var = getenv(path + 7); + if (!var) { + fprintf(stderr, + "environment variable \"%s\" is empty\n", path + 7); + exit(1); + } + path = var; + } + + if (!strncmp(path, "pkcs11:", 7)) { + ret = engine_get_pub_key(path, &key); + if (ret) + exit(1); + } else { + ret = pem_get_pub_key(path, &key); + if (ret) + exit(1); + } + + ret = gen_key_ecdsa(key, keyname, key_name_c); + if (ret) + ret = gen_key_rsa(key, keyname, key_name_c); + + return 0; +} + int main(int argc, char *argv[]) { char *path, *keyname; @@ -515,6 +645,7 @@ int main(int argc, char *argv[]) else fprintf(outfilep, "\tsignature {\n"); } else if (standalone) { + fprintf(outfilep, "#include <ecdsa.h>\n"); fprintf(outfilep, "#include <rsa.h>\n"); } -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 12/19] keytoc: add ecdsa support 2024-08-01 5:57 ` [PATCH v2 12/19] keytoc: add ecdsa support Sascha Hauer @ 2024-08-05 11:04 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 11:04 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > This extends the keytoc utility to also handle ecdsa keys. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > scripts/keytoc.c | 191 +++++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 161 insertions(+), 30 deletions(-) > > diff --git a/scripts/keytoc.c b/scripts/keytoc.c > index 891425cecc..0883ca64f7 100644 > --- a/scripts/keytoc.c > +++ b/scripts/keytoc.c > @@ -20,6 +20,8 @@ > #include <openssl/engine.h> > #include <openssl/provider.h> > #include <openssl/core_names.h> > +#include <openssl/param_build.h> > +#include <openssl/store.h> > > static int dts, standalone; > > @@ -377,44 +379,131 @@ static int print_bignum(BIGNUM *num, int num_bits) > return 0; > } > > -static int gen_key(const char *keyname, const char *path) > +/* > + * When imported from a HSM the key doesn't have the EC point parameters, Can you add a TODO: at the start, so it's more apparent, that there is something to do? > + * only the pubkey itself exists. Exporting the pubkey and creating a new > + * pkey from it resolves this. This can likely (hopefully) be improved, but > + * I don't have an idea how. > + */ > +static EVP_PKEY *reimport_key(EVP_PKEY *pkey) > { > - BIGNUM *modulus, *r_squared; > - uint64_t exponent = 0; > - uint32_t n0_inv; > + char group[128] = {}; > + size_t outlen; > + OSSL_PARAM *params; > + OSSL_PARAM_BLD *param_bld = NULL; > + unsigned char pub[128] = {}; > + size_t len; > + EVP_PKEY *pkey_out = NULL; > + EVP_PKEY_CTX *pkey_ctx; > int ret; > - int bits; > - EVP_PKEY *key; > - char *tmp, *key_name_c; > > - tmp = key_name_c = strdup(keyname); > + ret = EVP_PKEY_get_utf8_string_param(pkey, "group", group, sizeof(group), &outlen); Just pass in NULL for the final parameter if it's unused? > + if (dts) { > + fprintf(outfilep, "\t\tkey-%s {\n", key_name_c); > + fprintf(outfilep, "\t\t\tecdsa,x-point = <"); > + print_bignum(key_x, bits); > + fprintf(outfilep, ">;\n"); > + fprintf(outfilep, "\t\t\tecdsa,y-point = <"); > + print_bignum(key_y, bits); > + fprintf(outfilep, ">;\n"); > + fprintf(outfilep, "\t\t\tecdsa,curve = \"%s\";\n", group); > + fprintf(outfilep, "\t\t};\n"); Hmm, why no key-name-hint? > } else { > - ret = pem_get_pub_key(path, &key); > - if (ret) > - exit(1); > + fprintf(outfilep, "\nstatic uint32_t %s_x[] = {", key_name_c); > + print_bignum(key_x, bits); > + fprintf(outfilep, "\n};\n\n"); > + > + fprintf(outfilep, "static uint32_t %s_y[] = {", key_name_c); > + print_bignum(key_y, bits); > + fprintf(outfilep, "\n};\n\n"); > + > + fprintf(outfilep, "static struct ecdsa_public_key %s = {\n", key_name_c); > + > + fprintf(outfilep, "\t.curve_name = \"%s\",\n", group); > + fprintf(outfilep, "\t.x = %s_x,\n", key_name_c); > + fprintf(outfilep, "\t.y = %s_y,\n", key_name_c); > + fprintf(outfilep, "};\n"); > + if (!standalone) > + fprintf(outfilep, "\nstruct ecdsa_public_key *%s_ecdsa_p __attribute__((section(\".ecdsa_keys.rodata.%s\"))) = &%s;\n", > + key_name_c, key_name_c, key_name_c); > } > + ret = gen_key_ecdsa(key, keyname, key_name_c); > + if (ret) > + ret = gen_key_rsa(key, keyname, key_name_c); > + > + return 0; > +} > + > int main(int argc, char *argv[]) > { > char *path, *keyname; > @@ -515,6 +645,7 @@ int main(int argc, char *argv[]) > else > fprintf(outfilep, "\tsignature {\n"); > } else if (standalone) { > + fprintf(outfilep, "#include <ecdsa.h>\n"); This is being used before it was added. > fprintf(outfilep, "#include <rsa.h>\n"); > } > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 13/19] keytoc: Let openssl_error() take a format string 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (11 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 12/19] keytoc: add ecdsa support Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:22 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 14/19] keytoc: clarify error messages Sascha Hauer ` (6 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List Make openssl_error() a bit more versatile. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/keytoc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/keytoc.c b/scripts/keytoc.c index 0883ca64f7..aa36ba02e1 100644 --- a/scripts/keytoc.c +++ b/scripts/keytoc.c @@ -25,11 +25,14 @@ static int dts, standalone; -static int openssl_error(const char *msg) +static int openssl_error(const char *fmt, ...) { + va_list va; unsigned long sslErr = ERR_get_error(); - fprintf(stderr, "%s", msg); + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); fprintf(stderr, ": %s\n", ERR_error_string(sslErr, 0)); -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 13/19] keytoc: Let openssl_error() take a format string 2024-08-01 5:57 ` [PATCH v2 13/19] keytoc: Let openssl_error() take a format string Sascha Hauer @ 2024-08-05 10:22 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:22 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > Make openssl_error() a bit more versatile. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/keytoc.c | 7 +++++-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/scripts/keytoc.c b/scripts/keytoc.c > index 0883ca64f7..aa36ba02e1 100644 > --- a/scripts/keytoc.c > +++ b/scripts/keytoc.c > @@ -25,11 +25,14 @@ > > static int dts, standalone; > > -static int openssl_error(const char *msg) > +static int openssl_error(const char *fmt, ...) > { > + va_list va; > unsigned long sslErr = ERR_get_error(); > > - fprintf(stderr, "%s", msg); > + va_start(va, fmt); > + vfprintf(stderr, fmt, va); > + va_end(va); > fprintf(stderr, ": %s\n", > ERR_error_string(sslErr, 0)); > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 14/19] keytoc: clarify error messages 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (12 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 13/19] keytoc: Let openssl_error() take a format string Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:06 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 15/19] malloc: implement free_sensitive() Sascha Hauer ` (5 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List When we can't open the given path as certificate, we try reading it as a public key. Clarify the error message accordingly and add a comment about this. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- scripts/keytoc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/keytoc.c b/scripts/keytoc.c index aa36ba02e1..6c5ff9403d 100644 --- a/scripts/keytoc.c +++ b/scripts/keytoc.c @@ -57,7 +57,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) *pkey = NULL; f = fopen(path, "r"); if (!f) { - fprintf(stderr, "Couldn't open certificate: '%s': %s\n", + fprintf(stderr, "Couldn't open certificate '%s': %s\n", path, strerror(errno)); return -EACCES; } @@ -65,10 +65,11 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) /* Read the certificate */ cert = NULL; if (!PEM_read_X509(f, &cert, NULL, NULL)) { + /* Can't open certificate, maybe it's a pubkey */ rewind(f); key = PEM_read_PUBKEY(f, NULL, NULL, NULL); if (!key) { - openssl_error("Couldn't read certificate"); + openssl_error("Couldn't read certificate/pubkey %s\n", path); ret = -EINVAL; goto err_cert; } @@ -76,7 +77,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) /* Get the public key from the certificate. */ key = X509_get_pubkey(cert); if (!key) { - openssl_error("Couldn't read public key\n"); + openssl_error("Couldn't read public key from certificate\n"); ret = -EINVAL; goto err_pubkey; } -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 14/19] keytoc: clarify error messages 2024-08-01 5:57 ` [PATCH v2 14/19] keytoc: clarify error messages Sascha Hauer @ 2024-08-05 10:06 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:06 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > When we can't open the given path as certificate, we try reading it > as a public key. Clarify the error message accordingly and add a > comment about this. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > scripts/keytoc.c | 7 ++++--- > 1 file changed, 4 insertions(+), 3 deletions(-) > > diff --git a/scripts/keytoc.c b/scripts/keytoc.c > index aa36ba02e1..6c5ff9403d 100644 > --- a/scripts/keytoc.c > +++ b/scripts/keytoc.c > @@ -57,7 +57,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > *pkey = NULL; > f = fopen(path, "r"); > if (!f) { > - fprintf(stderr, "Couldn't open certificate: '%s': %s\n", > + fprintf(stderr, "Couldn't open certificate '%s': %s\n", > path, strerror(errno)); > return -EACCES; > } > @@ -65,10 +65,11 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > /* Read the certificate */ > cert = NULL; > if (!PEM_read_X509(f, &cert, NULL, NULL)) { > + /* Can't open certificate, maybe it's a pubkey */ > rewind(f); > key = PEM_read_PUBKEY(f, NULL, NULL, NULL); > if (!key) { > - openssl_error("Couldn't read certificate"); > + openssl_error("Couldn't read certificate/pubkey %s\n", path); > ret = -EINVAL; > goto err_cert; > } > @@ -76,7 +77,7 @@ static int pem_get_pub_key(const char *path, EVP_PKEY **pkey) > /* Get the public key from the certificate. */ > key = X509_get_pubkey(cert); > if (!key) { > - openssl_error("Couldn't read public key\n"); > + openssl_error("Couldn't read public key from certificate\n"); > ret = -EINVAL; > goto err_pubkey; > } -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 15/19] malloc: implement free_sensitive() 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (13 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 14/19] keytoc: clarify error messages Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:17 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 16/19] Add elliptic curve cryptography (ECC) helper functions Sascha Hauer ` (4 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List barebox sometimes stores sensitive data in memory. Add a (k)free_sensitive() function which zeroes out the memory before freeing it. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- common/dlmalloc.c | 15 +++++++++++++++ common/tlsf_malloc.c | 11 +++++++++++ include/dma.h | 5 +++++ include/linux/slab.h | 5 +++++ include/malloc.h | 1 + 5 files changed, 37 insertions(+) diff --git a/common/dlmalloc.c b/common/dlmalloc.c index c41487d54b..0e23399b2b 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -1431,6 +1431,21 @@ void free(void *mem) frontlink(p, sz, idx, bck, fwd); } +void free_sensitive(void *mem) +{ + mchunkptr p; + size_t size; + + if (!mem) + return; + + p = mem2chunk(mem); + size = chunksize(p); + if (size) + memset(mem, size, 0x0); + + free(mem); +} /* Realloc algorithm: diff --git a/common/tlsf_malloc.c b/common/tlsf_malloc.c index 981f09de41..5bcbbcd2f8 100644 --- a/common/tlsf_malloc.c +++ b/common/tlsf_malloc.c @@ -38,6 +38,17 @@ void free(void *mem) } EXPORT_SYMBOL(free); +void free_sensitive(void *mem) +{ + size_t size; + + size = tlsf_block_size(mem); + if (size) + memset(mem, size, 0x0); + + tlsf_free(tlsf_mem_pool, mem); +} + void *realloc(void *oldmem, size_t bytes) { void *mem = tlsf_realloc(tlsf_mem_pool, oldmem, bytes); diff --git a/include/dma.h b/include/dma.h index 4fcd114bb6..c2b1bee358 100644 --- a/include/dma.h +++ b/include/dma.h @@ -41,6 +41,11 @@ static inline void dma_free(void *mem) free(mem); } +static inline void dma_free_sensitive(void *mem) +{ + free_sensitive(mem); +} + #define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) #define DMA_MASK_NONE 0x0ULL diff --git a/include/linux/slab.h b/include/linux/slab.h index eba3593d75..8c82e19866 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -67,6 +67,11 @@ static inline void kfree(const void *mem) dma_free((void *)mem); } +static inline void kfree_sensitive(const void *objp) +{ + dma_free_sensitive((void *)objp); +} + static inline void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags) { void *mem = kmalloc(cache->size, flags); diff --git a/include/malloc.h b/include/malloc.h index d63853b91e..c25bbf6949 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -7,6 +7,7 @@ void *malloc(size_t) __alloc_size(1); void free(void *); +void free_sensitive(void *); void *realloc(void *, size_t) __realloc_size(2); void *memalign(size_t, size_t) __alloc_size(2); void *calloc(size_t, size_t) __alloc_size(1, 2); -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 15/19] malloc: implement free_sensitive() 2024-08-01 5:57 ` [PATCH v2 15/19] malloc: implement free_sensitive() Sascha Hauer @ 2024-08-05 10:17 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:17 UTC (permalink / raw) To: Sascha Hauer, Barebox List Hello Sascha, On 01.08.24 07:57, Sascha Hauer wrote: > barebox sometimes stores sensitive data in memory. Add a > (k)free_sensitive() function which zeroes out the memory before freeing it. Could you export a malloc_usable_size() from the allocators and use that to implement free_sensitive? > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > +void free_sensitive(void *mem) > +{ > + mchunkptr p; > + size_t size; > + > + if (!mem) > + return; > + > + p = mem2chunk(mem); > + size = chunksize(p); > + if (size) > + memset(mem, size, 0x0); buffer size is the last argument, so this is a no-op. Please implement a memzero_explicit operation like Linux does and use it here as that doesn't risk confusion the last two parameters. > +void free_sensitive(void *mem) > +{ > + size_t size; > + > + size = tlsf_block_size(mem); > + if (size) > + memset(mem, size, 0x0); Same issue. Cheers, Ahmad -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 16/19] Add elliptic curve cryptography (ECC) helper functions 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (14 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 15/19] malloc: implement free_sensitive() Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 11:32 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 17/19] crypto: add ECDSA support Sascha Hauer ` (3 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List This ports the functions needed for supporting elliptic curve cryptography (ECC) from the Kernel. The code is taken from Linux-6.10 and mostly unchanged. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- crypto/Kconfig | 3 + crypto/Makefile | 1 + crypto/ecc.c | 1661 +++++++++++++++++++++++++++++++++ crypto/ecc_curve_defs.h | 155 +++ include/crypto/ecc_curve.h | 62 ++ include/crypto/ecdh.h | 83 ++ include/crypto/internal/ecc.h | 278 ++++++ 7 files changed, 2243 insertions(+) create mode 100644 crypto/ecc.c create mode 100644 crypto/ecc_curve_defs.h create mode 100644 include/crypto/ecc_curve.h create mode 100644 include/crypto/ecdh.h create mode 100644 include/crypto/internal/ecc.h diff --git a/crypto/Kconfig b/crypto/Kconfig index 78b499f646..e953ef5e15 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -153,4 +153,7 @@ config JWT select BASE64 select CRYPTO_RSA +config CRYPTO_ECC + bool + endmenu diff --git a/crypto/Makefile b/crypto/Makefile index e84360a8c7..83c05761de 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -18,6 +18,7 @@ obj-y += memneq.o obj-$(CONFIG_CRYPTO_PBKDF2) += pbkdf2.o obj-$(CONFIG_CRYPTO_RSA) += rsa.o obj-$(CONFIG_CRYPTO_KEYSTORE) += keystore.o +obj-$(CONFIG_CRYPTO_ECC) += ecc.o obj-$(CONFIG_JWT) += jwt.o diff --git a/crypto/ecc.c b/crypto/ecc.c new file mode 100644 index 0000000000..a0ab962262 --- /dev/null +++ b/crypto/ecc.c @@ -0,0 +1,1661 @@ +/* + * Copyright (c) 2013, 2014 Kenneth MacKay. All rights reserved. + * Copyright (c) 2019 Vitaly Chikunov <vt@altlinux.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <common.h> +#include <stdlib.h> +#include <crypto/ecc_curve.h> +#include <crypto/ecdh.h> +#include <crypto/internal/ecc.h> +#include <asm/unaligned.h> + +#include "ecc_curve_defs.h" + +typedef struct { + u64 m_low; + u64 m_high; +} uint128_t; + +/* Returns curv25519 curve param */ +const struct ecc_curve *ecc_get_curve25519(void) +{ + return &ecc_25519; +} +EXPORT_SYMBOL(ecc_get_curve25519); + +const struct ecc_curve *ecc_get_curve(unsigned int curve_id) +{ + switch (curve_id) { + case ECC_CURVE_NIST_P192: + return &nist_p192; + case ECC_CURVE_NIST_P256: + return &nist_p256; + case ECC_CURVE_NIST_P384: + return &nist_p384; + case ECC_CURVE_NIST_P521: + return &nist_p521; + default: + return NULL; + } +} +EXPORT_SYMBOL(ecc_get_curve); + +void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes, + u64 *out, unsigned int ndigits) +{ + int diff = ndigits - DIV_ROUND_UP(nbytes, sizeof(u64)); + unsigned int o = nbytes & 7; + __be64 msd = 0; + + /* diff > 0: not enough input bytes: set most significant digits to 0 */ + if (diff > 0) { + ndigits -= diff; + memset(&out[ndigits - 1], 0, diff * sizeof(u64)); + } + + if (o) { + memcpy((u8 *)&msd + sizeof(msd) - o, in, o); + out[--ndigits] = be64_to_cpu(msd); + in += o; + } + ecc_swap_digits(in, out, ndigits); +} +EXPORT_SYMBOL(ecc_digits_from_bytes); + +static u64 *ecc_alloc_digits_space(unsigned int ndigits) +{ + size_t len = ndigits * sizeof(u64); + + if (!len) + return NULL; + + return kmalloc(len, GFP_KERNEL); +} + +static void ecc_free_digits_space(u64 *space) +{ + kfree_sensitive(space); +} + +struct ecc_point *ecc_alloc_point(unsigned int ndigits) +{ + struct ecc_point *p = kmalloc(sizeof(*p), GFP_KERNEL); + + if (!p) + return NULL; + + p->x = ecc_alloc_digits_space(ndigits); + if (!p->x) + goto err_alloc_x; + + p->y = ecc_alloc_digits_space(ndigits); + if (!p->y) + goto err_alloc_y; + + p->ndigits = ndigits; + + return p; + +err_alloc_y: + ecc_free_digits_space(p->x); +err_alloc_x: + kfree(p); + return NULL; +} +EXPORT_SYMBOL(ecc_alloc_point); + +void ecc_free_point(struct ecc_point *p) +{ + if (!p) + return; + + kfree_sensitive(p->x); + kfree_sensitive(p->y); + kfree_sensitive(p); +} +EXPORT_SYMBOL(ecc_free_point); + +static void vli_clear(u64 *vli, unsigned int ndigits) +{ + int i; + + for (i = 0; i < ndigits; i++) + vli[i] = 0; +} + +/* Returns true if vli == 0, false otherwise. */ +bool vli_is_zero(const u64 *vli, unsigned int ndigits) +{ + int i; + + for (i = 0; i < ndigits; i++) { + if (vli[i]) + return false; + } + + return true; +} +EXPORT_SYMBOL(vli_is_zero); + +/* Returns nonzero if bit of vli is set. */ +static u64 vli_test_bit(const u64 *vli, unsigned int bit) +{ + return (vli[bit / 64] & ((u64)1 << (bit % 64))); +} + +static bool vli_is_negative(const u64 *vli, unsigned int ndigits) +{ + return vli_test_bit(vli, ndigits * 64 - 1); +} + +/* Counts the number of 64-bit "digits" in vli. */ +static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits) +{ + int i; + + /* Search from the end until we find a non-zero digit. + * We do it in reverse because we expect that most digits will + * be nonzero. + */ + for (i = ndigits - 1; i >= 0 && vli[i] == 0; i--); + + return (i + 1); +} + +/* Counts the number of bits required for vli. */ +unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits) +{ + unsigned int i, num_digits; + u64 digit; + + num_digits = vli_num_digits(vli, ndigits); + if (num_digits == 0) + return 0; + + digit = vli[num_digits - 1]; + for (i = 0; digit; i++) + digit >>= 1; + + return ((num_digits - 1) * 64 + i); +} +EXPORT_SYMBOL(vli_num_bits); + +/* Set dest from unaligned bit string src. */ +void vli_from_be64(u64 *dest, const void *src, unsigned int ndigits) +{ + int i; + const u64 *from = src; + + for (i = 0; i < ndigits; i++) + dest[i] = get_unaligned_be64(&from[ndigits - 1 - i]); +} +EXPORT_SYMBOL(vli_from_be64); + +void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits) +{ + int i; + const u64 *from = src; + + for (i = 0; i < ndigits; i++) + dest[i] = get_unaligned_le64(&from[i]); +} +EXPORT_SYMBOL(vli_from_le64); + +/* Sets dest = src. */ +static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits) +{ + int i; + + for (i = 0; i < ndigits; i++) + dest[i] = src[i]; +} + +/* Returns sign of left - right. */ +int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits) +{ + int i; + + for (i = ndigits - 1; i >= 0; i--) { + if (left[i] > right[i]) + return 1; + else if (left[i] < right[i]) + return -1; + } + + return 0; +} +EXPORT_SYMBOL(vli_cmp); + +/* Computes result = in << c, returning carry. Can modify in place + * (if result == in). 0 < shift < 64. + */ +static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift, + unsigned int ndigits) +{ + u64 carry = 0; + int i; + + for (i = 0; i < ndigits; i++) { + u64 temp = in[i]; + + result[i] = (temp << shift) | carry; + carry = temp >> (64 - shift); + } + + return carry; +} + +/* Computes vli = vli >> 1. */ +static void vli_rshift1(u64 *vli, unsigned int ndigits) +{ + u64 *end = vli; + u64 carry = 0; + + vli += ndigits; + + while (vli-- > end) { + u64 temp = *vli; + *vli = (temp >> 1) | carry; + carry = temp << 63; + } +} + +/* Computes result = left + right, returning carry. Can modify in place. */ +static u64 vli_add(u64 *result, const u64 *left, const u64 *right, + unsigned int ndigits) +{ + u64 carry = 0; + int i; + + for (i = 0; i < ndigits; i++) { + u64 sum; + + sum = left[i] + right[i] + carry; + if (sum != left[i]) + carry = (sum < left[i]); + + result[i] = sum; + } + + return carry; +} + +/* Computes result = left + right, returning carry. Can modify in place. */ +static u64 vli_uadd(u64 *result, const u64 *left, u64 right, + unsigned int ndigits) +{ + u64 carry = right; + int i; + + for (i = 0; i < ndigits; i++) { + u64 sum; + + sum = left[i] + carry; + if (sum != left[i]) + carry = (sum < left[i]); + else + carry = !!carry; + + result[i] = sum; + } + + return carry; +} + +/* Computes result = left - right, returning borrow. Can modify in place. */ +u64 vli_sub(u64 *result, const u64 *left, const u64 *right, + unsigned int ndigits) +{ + u64 borrow = 0; + int i; + + for (i = 0; i < ndigits; i++) { + u64 diff; + + diff = left[i] - right[i] - borrow; + if (diff != left[i]) + borrow = (diff > left[i]); + + result[i] = diff; + } + + return borrow; +} +EXPORT_SYMBOL(vli_sub); + +/* Computes result = left - right, returning borrow. Can modify in place. */ +static u64 vli_usub(u64 *result, const u64 *left, u64 right, + unsigned int ndigits) +{ + u64 borrow = right; + int i; + + for (i = 0; i < ndigits; i++) { + u64 diff; + + diff = left[i] - borrow; + if (diff != left[i]) + borrow = (diff > left[i]); + + result[i] = diff; + } + + return borrow; +} + +static uint128_t mul_64_64(u64 left, u64 right) +{ + uint128_t result; +#if defined(CONFIG_ARCH_SUPPORTS_INT128) + unsigned __int128 m = (unsigned __int128)left * right; + + result.m_low = m; + result.m_high = m >> 64; +#else + u64 a0 = left & 0xffffffffull; + u64 a1 = left >> 32; + u64 b0 = right & 0xffffffffull; + u64 b1 = right >> 32; + u64 m0 = a0 * b0; + u64 m1 = a0 * b1; + u64 m2 = a1 * b0; + u64 m3 = a1 * b1; + + m2 += (m0 >> 32); + m2 += m1; + + /* Overflow */ + if (m2 < m1) + m3 += 0x100000000ull; + + result.m_low = (m0 & 0xffffffffull) | (m2 << 32); + result.m_high = m3 + (m2 >> 32); +#endif + return result; +} + +static uint128_t add_128_128(uint128_t a, uint128_t b) +{ + uint128_t result; + + result.m_low = a.m_low + b.m_low; + result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); + + return result; +} + +static void vli_mult(u64 *result, const u64 *left, const u64 *right, + unsigned int ndigits) +{ + uint128_t r01 = { 0, 0 }; + u64 r2 = 0; + unsigned int i, k; + + /* Compute each digit of result in sequence, maintaining the + * carries. + */ + for (k = 0; k < ndigits * 2 - 1; k++) { + unsigned int min; + + if (k < ndigits) + min = 0; + else + min = (k + 1) - ndigits; + + for (i = min; i <= k && i < ndigits; i++) { + uint128_t product; + + product = mul_64_64(left[i], right[k - i]); + + r01 = add_128_128(r01, product); + r2 += (r01.m_high < product.m_high); + } + + result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = r2; + r2 = 0; + } + + result[ndigits * 2 - 1] = r01.m_low; +} + +/* Compute product = left * right, for a small right value. */ +static void vli_umult(u64 *result, const u64 *left, u32 right, + unsigned int ndigits) +{ + uint128_t r01 = { 0 }; + unsigned int k; + + for (k = 0; k < ndigits; k++) { + uint128_t product; + + product = mul_64_64(left[k], right); + r01 = add_128_128(r01, product); + /* no carry */ + result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = 0; + } + result[k] = r01.m_low; + for (++k; k < ndigits * 2; k++) + result[k] = 0; +} + +static void vli_square(u64 *result, const u64 *left, unsigned int ndigits) +{ + uint128_t r01 = { 0, 0 }; + u64 r2 = 0; + int i, k; + + for (k = 0; k < ndigits * 2 - 1; k++) { + unsigned int min; + + if (k < ndigits) + min = 0; + else + min = (k + 1) - ndigits; + + for (i = min; i <= k && i <= k - i; i++) { + uint128_t product; + + product = mul_64_64(left[i], left[k - i]); + + if (i < k - i) { + r2 += product.m_high >> 63; + product.m_high = (product.m_high << 1) | + (product.m_low >> 63); + product.m_low <<= 1; + } + + r01 = add_128_128(r01, product); + r2 += (r01.m_high < product.m_high); + } + + result[k] = r01.m_low; + r01.m_low = r01.m_high; + r01.m_high = r2; + r2 = 0; + } + + result[ndigits * 2 - 1] = r01.m_low; +} + +/* Computes result = (left + right) % mod. + * Assumes that left < mod and right < mod, result != mod. + */ +static void vli_mod_add(u64 *result, const u64 *left, const u64 *right, + const u64 *mod, unsigned int ndigits) +{ + u64 carry; + + carry = vli_add(result, left, right, ndigits); + + /* result > mod (result = mod + remainder), so subtract mod to + * get remainder. + */ + if (carry || vli_cmp(result, mod, ndigits) >= 0) + vli_sub(result, result, mod, ndigits); +} + +/* Computes result = (left - right) % mod. + * Assumes that left < mod and right < mod, result != mod. + */ +static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right, + const u64 *mod, unsigned int ndigits) +{ + u64 borrow = vli_sub(result, left, right, ndigits); + + /* In this case, p_result == -diff == (max int) - diff. + * Since -x % d == d - x, we can get the correct result from + * result + mod (with overflow). + */ + if (borrow) + vli_add(result, result, mod, ndigits); +} + +/* + * Computes result = product % mod + * for special form moduli: p = 2^k-c, for small c (note the minus sign) + * + * References: + * R. Crandall, C. Pomerance. Prime Numbers: A Computational Perspective. + * 9 Fast Algorithms for Large-Integer Arithmetic. 9.2.3 Moduli of special form + * Algorithm 9.2.13 (Fast mod operation for special-form moduli). + */ +static void vli_mmod_special(u64 *result, const u64 *product, + const u64 *mod, unsigned int ndigits) +{ + u64 c = -mod[0]; + u64 t[ECC_MAX_DIGITS * 2]; + u64 r[ECC_MAX_DIGITS * 2]; + + vli_set(r, product, ndigits * 2); + while (!vli_is_zero(r + ndigits, ndigits)) { + vli_umult(t, r + ndigits, c, ndigits); + vli_clear(r + ndigits, ndigits); + vli_add(r, r, t, ndigits * 2); + } + vli_set(t, mod, ndigits); + vli_clear(t + ndigits, ndigits); + while (vli_cmp(r, t, ndigits * 2) >= 0) + vli_sub(r, r, t, ndigits * 2); + vli_set(result, r, ndigits); +} + +/* + * Computes result = product % mod + * for special form moduli: p = 2^{k-1}+c, for small c (note the plus sign) + * where k-1 does not fit into qword boundary by -1 bit (such as 255). + + * References (loosely based on): + * A. Menezes, P. van Oorschot, S. Vanstone. Handbook of Applied Cryptography. + * 14.3.4 Reduction methods for moduli of special form. Algorithm 14.47. + * URL: http://cacr.uwaterloo.ca/hac/about/chap14.pdf + * + * H. Cohen, G. Frey, R. Avanzi, C. Doche, T. Lange, K. Nguyen, F. Vercauteren. + * Handbook of Elliptic and Hyperelliptic Curve Cryptography. + * Algorithm 10.25 Fast reduction for special form moduli + */ +static void vli_mmod_special2(u64 *result, const u64 *product, + const u64 *mod, unsigned int ndigits) +{ + u64 c2 = mod[0] * 2; + u64 q[ECC_MAX_DIGITS]; + u64 r[ECC_MAX_DIGITS * 2]; + u64 m[ECC_MAX_DIGITS * 2]; /* expanded mod */ + int carry; /* last bit that doesn't fit into q */ + int i; + + vli_set(m, mod, ndigits); + vli_clear(m + ndigits, ndigits); + + vli_set(r, product, ndigits); + /* q and carry are top bits */ + vli_set(q, product + ndigits, ndigits); + vli_clear(r + ndigits, ndigits); + carry = vli_is_negative(r, ndigits); + if (carry) + r[ndigits - 1] &= (1ull << 63) - 1; + for (i = 1; carry || !vli_is_zero(q, ndigits); i++) { + u64 qc[ECC_MAX_DIGITS * 2]; + + vli_umult(qc, q, c2, ndigits); + if (carry) + vli_uadd(qc, qc, mod[0], ndigits * 2); + vli_set(q, qc + ndigits, ndigits); + vli_clear(qc + ndigits, ndigits); + carry = vli_is_negative(qc, ndigits); + if (carry) + qc[ndigits - 1] &= (1ull << 63) - 1; + if (i & 1) + vli_sub(r, r, qc, ndigits * 2); + else + vli_add(r, r, qc, ndigits * 2); + } + while (vli_is_negative(r, ndigits * 2)) + vli_add(r, r, m, ndigits * 2); + while (vli_cmp(r, m, ndigits * 2) >= 0) + vli_sub(r, r, m, ndigits * 2); + + vli_set(result, r, ndigits); +} + +/* + * Computes result = product % mod, where product is 2N words long. + * Reference: Ken MacKay's micro-ecc. + * Currently only designed to work for curve_p or curve_n. + */ +static void vli_mmod_slow(u64 *result, u64 *product, const u64 *mod, + unsigned int ndigits) +{ + u64 mod_m[2 * ECC_MAX_DIGITS]; + u64 tmp[2 * ECC_MAX_DIGITS]; + u64 *v[2] = { tmp, product }; + u64 carry = 0; + unsigned int i; + /* Shift mod so its highest set bit is at the maximum position. */ + int shift = (ndigits * 2 * 64) - vli_num_bits(mod, ndigits); + int word_shift = shift / 64; + int bit_shift = shift % 64; + + vli_clear(mod_m, word_shift); + if (bit_shift > 0) { + for (i = 0; i < ndigits; ++i) { + mod_m[word_shift + i] = (mod[i] << bit_shift) | carry; + carry = mod[i] >> (64 - bit_shift); + } + } else + vli_set(mod_m + word_shift, mod, ndigits); + + for (i = 1; shift >= 0; --shift) { + u64 borrow = 0; + unsigned int j; + + for (j = 0; j < ndigits * 2; ++j) { + u64 diff = v[i][j] - mod_m[j] - borrow; + + if (diff != v[i][j]) + borrow = (diff > v[i][j]); + v[1 - i][j] = diff; + } + i = !(i ^ borrow); /* Swap the index if there was no borrow */ + vli_rshift1(mod_m, ndigits); + mod_m[ndigits - 1] |= mod_m[ndigits] << (64 - 1); + vli_rshift1(mod_m + ndigits, ndigits); + } + vli_set(result, v[i], ndigits); +} + +/* Computes result = product % mod using Barrett's reduction with precomputed + * value mu appended to the mod after ndigits, mu = (2^{2w} / mod) and have + * length ndigits + 1, where mu * (2^w - 1) should not overflow ndigits + * boundary. + * + * Reference: + * R. Brent, P. Zimmermann. Modern Computer Arithmetic. 2010. + * 2.4.1 Barrett's algorithm. Algorithm 2.5. + */ +static void vli_mmod_barrett(u64 *result, u64 *product, const u64 *mod, + unsigned int ndigits) +{ + u64 q[ECC_MAX_DIGITS * 2]; + u64 r[ECC_MAX_DIGITS * 2]; + const u64 *mu = mod + ndigits; + + vli_mult(q, product + ndigits, mu, ndigits); + if (mu[ndigits]) + vli_add(q + ndigits, q + ndigits, product + ndigits, ndigits); + vli_mult(r, mod, q + ndigits, ndigits); + vli_sub(r, product, r, ndigits * 2); + while (!vli_is_zero(r + ndigits, ndigits) || + vli_cmp(r, mod, ndigits) != -1) { + u64 carry; + + carry = vli_sub(r, r, mod, ndigits); + vli_usub(r + ndigits, r + ndigits, carry, ndigits); + } + vli_set(result, r, ndigits); +} + +/* Computes p_result = p_product % curve_p. + * See algorithm 5 and 6 from + * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf + */ +static void vli_mmod_fast_192(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + const unsigned int ndigits = ECC_CURVE_NIST_P192_DIGITS; + int carry; + + vli_set(result, product, ndigits); + + vli_set(tmp, &product[3], ndigits); + carry = vli_add(result, result, tmp, ndigits); + + tmp[0] = 0; + tmp[1] = product[3]; + tmp[2] = product[4]; + carry += vli_add(result, result, tmp, ndigits); + + tmp[0] = tmp[1] = product[5]; + tmp[2] = 0; + carry += vli_add(result, result, tmp, ndigits); + + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) + carry -= vli_sub(result, result, curve_prime, ndigits); +} + +/* Computes result = product % curve_prime + * from http://www.nsa.gov/ia/_files/nist-routines.pdf + */ +static void vli_mmod_fast_256(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + int carry; + const unsigned int ndigits = ECC_CURVE_NIST_P256_DIGITS; + + /* t */ + vli_set(result, product, ndigits); + + /* s1 */ + tmp[0] = 0; + tmp[1] = product[5] & 0xffffffff00000000ull; + tmp[2] = product[6]; + tmp[3] = product[7]; + carry = vli_lshift(tmp, tmp, 1, ndigits); + carry += vli_add(result, result, tmp, ndigits); + + /* s2 */ + tmp[1] = product[6] << 32; + tmp[2] = (product[6] >> 32) | (product[7] << 32); + tmp[3] = product[7] >> 32; + carry += vli_lshift(tmp, tmp, 1, ndigits); + carry += vli_add(result, result, tmp, ndigits); + + /* s3 */ + tmp[0] = product[4]; + tmp[1] = product[5] & 0xffffffff; + tmp[2] = 0; + tmp[3] = product[7]; + carry += vli_add(result, result, tmp, ndigits); + + /* s4 */ + tmp[0] = (product[4] >> 32) | (product[5] << 32); + tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); + tmp[2] = product[7]; + tmp[3] = (product[6] >> 32) | (product[4] << 32); + carry += vli_add(result, result, tmp, ndigits); + + /* d1 */ + tmp[0] = (product[5] >> 32) | (product[6] << 32); + tmp[1] = (product[6] >> 32); + tmp[2] = 0; + tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); + carry -= vli_sub(result, result, tmp, ndigits); + + /* d2 */ + tmp[0] = product[6]; + tmp[1] = product[7]; + tmp[2] = 0; + tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); + carry -= vli_sub(result, result, tmp, ndigits); + + /* d3 */ + tmp[0] = (product[6] >> 32) | (product[7] << 32); + tmp[1] = (product[7] >> 32) | (product[4] << 32); + tmp[2] = (product[4] >> 32) | (product[5] << 32); + tmp[3] = (product[6] << 32); + carry -= vli_sub(result, result, tmp, ndigits); + + /* d4 */ + tmp[0] = product[7]; + tmp[1] = product[4] & 0xffffffff00000000ull; + tmp[2] = product[5]; + tmp[3] = product[6] & 0xffffffff00000000ull; + carry -= vli_sub(result, result, tmp, ndigits); + + if (carry < 0) { + do { + carry += vli_add(result, result, curve_prime, ndigits); + } while (carry < 0); + } else { + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) + carry -= vli_sub(result, result, curve_prime, ndigits); + } +} + +#define SL32OR32(x32, y32) (((u64)x32 << 32) | y32) +#define AND64H(x64) (x64 & 0xffFFffFF00000000ull) +#define AND64L(x64) (x64 & 0x00000000ffFFffFFull) + +/* Computes result = product % curve_prime + * from "Mathematical routines for the NIST prime elliptic curves" + */ +static void vli_mmod_fast_384(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + int carry; + const unsigned int ndigits = ECC_CURVE_NIST_P384_DIGITS; + + /* t */ + vli_set(result, product, ndigits); + + /* s1 */ + tmp[0] = 0; // 0 || 0 + tmp[1] = 0; // 0 || 0 + tmp[2] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[3] = product[11]>>32; // 0 ||a23 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry = vli_lshift(tmp, tmp, 1, ndigits); + carry += vli_add(result, result, tmp, ndigits); + + /* s2 */ + tmp[0] = product[6]; //a13||a12 + tmp[1] = product[7]; //a15||a14 + tmp[2] = product[8]; //a17||a16 + tmp[3] = product[9]; //a19||a18 + tmp[4] = product[10]; //a21||a20 + tmp[5] = product[11]; //a23||a22 + carry += vli_add(result, result, tmp, ndigits); + + /* s3 */ + tmp[0] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[1] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 + tmp[2] = SL32OR32(product[7], (product[6])>>32); //a14||a13 + tmp[3] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 + tmp[4] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 + tmp[5] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 + carry += vli_add(result, result, tmp, ndigits); + + /* s4 */ + tmp[0] = AND64H(product[11]); //a23|| 0 + tmp[1] = (product[10]<<32); //a20|| 0 + tmp[2] = product[6]; //a13||a12 + tmp[3] = product[7]; //a15||a14 + tmp[4] = product[8]; //a17||a16 + tmp[5] = product[9]; //a19||a18 + carry += vli_add(result, result, tmp, ndigits); + + /* s5 */ + tmp[0] = 0; // 0|| 0 + tmp[1] = 0; // 0|| 0 + tmp[2] = product[10]; //a21||a20 + tmp[3] = product[11]; //a23||a22 + tmp[4] = 0; // 0|| 0 + tmp[5] = 0; // 0|| 0 + carry += vli_add(result, result, tmp, ndigits); + + /* s6 */ + tmp[0] = AND64L(product[10]); // 0 ||a20 + tmp[1] = AND64H(product[10]); //a21|| 0 + tmp[2] = product[11]; //a23||a22 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry += vli_add(result, result, tmp, ndigits); + + /* d1 */ + tmp[0] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 + tmp[1] = SL32OR32(product[7], (product[6]>>32)); //a14||a13 + tmp[2] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 + tmp[3] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 + tmp[4] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 + tmp[5] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + carry -= vli_sub(result, result, tmp, ndigits); + + /* d2 */ + tmp[0] = (product[10]<<32); //a20|| 0 + tmp[1] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 + tmp[2] = (product[11]>>32); // 0 ||a23 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry -= vli_sub(result, result, tmp, ndigits); + + /* d3 */ + tmp[0] = 0; // 0 || 0 + tmp[1] = AND64H(product[11]); //a23|| 0 + tmp[2] = product[11]>>32; // 0 ||a23 + tmp[3] = 0; // 0 || 0 + tmp[4] = 0; // 0 || 0 + tmp[5] = 0; // 0 || 0 + carry -= vli_sub(result, result, tmp, ndigits); + + if (carry < 0) { + do { + carry += vli_add(result, result, curve_prime, ndigits); + } while (carry < 0); + } else { + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) + carry -= vli_sub(result, result, curve_prime, ndigits); + } + +} + +#undef SL32OR32 +#undef AND64H +#undef AND64L + +/* + * Computes result = product % curve_prime + * from "Recommendations for Discrete Logarithm-Based Cryptography: + * Elliptic Curve Domain Parameters" section G.1.4 + */ +static void vli_mmod_fast_521(u64 *result, const u64 *product, + const u64 *curve_prime, u64 *tmp) +{ + const unsigned int ndigits = ECC_CURVE_NIST_P521_DIGITS; + size_t i; + + /* Initialize result with lowest 521 bits from product */ + vli_set(result, product, ndigits); + result[8] &= 0x1ff; + + for (i = 0; i < ndigits; i++) + tmp[i] = (product[8 + i] >> 9) | (product[9 + i] << 55); + tmp[8] &= 0x1ff; + + vli_mod_add(result, result, tmp, curve_prime, ndigits); +} + +/* Computes result = product % curve_prime for different curve_primes. + * + * Note that curve_primes are distinguished just by heuristic check and + * not by complete conformance check. + */ +static bool vli_mmod_fast(u64 *result, u64 *product, + const struct ecc_curve *curve) +{ + u64 tmp[2 * ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; + + /* All NIST curves have name prefix 'nist_' */ + if (strncmp(curve->name, "nist_", 5) != 0) { + /* Try to handle Pseudo-Marsenne primes. */ + if (curve_prime[ndigits - 1] == -1ull) { + vli_mmod_special(result, product, curve_prime, + ndigits); + return true; + } else if (curve_prime[ndigits - 1] == 1ull << 63 && + curve_prime[ndigits - 2] == 0) { + vli_mmod_special2(result, product, curve_prime, + ndigits); + return true; + } + vli_mmod_barrett(result, product, curve_prime, ndigits); + return true; + } + + switch (ndigits) { + case ECC_CURVE_NIST_P192_DIGITS: + vli_mmod_fast_192(result, product, curve_prime, tmp); + break; + case ECC_CURVE_NIST_P256_DIGITS: + vli_mmod_fast_256(result, product, curve_prime, tmp); + break; + case ECC_CURVE_NIST_P384_DIGITS: + vli_mmod_fast_384(result, product, curve_prime, tmp); + break; + case ECC_CURVE_NIST_P521_DIGITS: + vli_mmod_fast_521(result, product, curve_prime, tmp); + break; + default: + pr_err("ecc: unsupported digits size!\n"); + return false; + } + + return true; +} + +/* Computes result = (left * right) % mod. + * Assumes that mod is big enough curve order. + */ +void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right, + const u64 *mod, unsigned int ndigits) +{ + u64 product[ECC_MAX_DIGITS * 2]; + + vli_mult(product, left, right, ndigits); + vli_mmod_slow(result, product, mod, ndigits); +} +EXPORT_SYMBOL(vli_mod_mult_slow); + +/* Computes result = (left * right) % curve_prime. */ +static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right, + const struct ecc_curve *curve) +{ + u64 product[2 * ECC_MAX_DIGITS]; + + vli_mult(product, left, right, curve->g.ndigits); + vli_mmod_fast(result, product, curve); +} + +/* Computes result = left^2 % curve_prime. */ +static void vli_mod_square_fast(u64 *result, const u64 *left, + const struct ecc_curve *curve) +{ + u64 product[2 * ECC_MAX_DIGITS]; + + vli_square(product, left, curve->g.ndigits); + vli_mmod_fast(result, product, curve); +} + +#define EVEN(vli) (!(vli[0] & 1)) +/* Computes result = (1 / p_input) % mod. All VLIs are the same size. + * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" + * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf + */ +void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod, + unsigned int ndigits) +{ + u64 a[ECC_MAX_DIGITS], b[ECC_MAX_DIGITS]; + u64 u[ECC_MAX_DIGITS], v[ECC_MAX_DIGITS]; + u64 carry; + int cmp_result; + + if (vli_is_zero(input, ndigits)) { + vli_clear(result, ndigits); + return; + } + + vli_set(a, input, ndigits); + vli_set(b, mod, ndigits); + vli_clear(u, ndigits); + u[0] = 1; + vli_clear(v, ndigits); + + while ((cmp_result = vli_cmp(a, b, ndigits)) != 0) { + carry = 0; + + if (EVEN(a)) { + vli_rshift1(a, ndigits); + + if (!EVEN(u)) + carry = vli_add(u, u, mod, ndigits); + + vli_rshift1(u, ndigits); + if (carry) + u[ndigits - 1] |= 0x8000000000000000ull; + } else if (EVEN(b)) { + vli_rshift1(b, ndigits); + + if (!EVEN(v)) + carry = vli_add(v, v, mod, ndigits); + + vli_rshift1(v, ndigits); + if (carry) + v[ndigits - 1] |= 0x8000000000000000ull; + } else if (cmp_result > 0) { + vli_sub(a, a, b, ndigits); + vli_rshift1(a, ndigits); + + if (vli_cmp(u, v, ndigits) < 0) + vli_add(u, u, mod, ndigits); + + vli_sub(u, u, v, ndigits); + if (!EVEN(u)) + carry = vli_add(u, u, mod, ndigits); + + vli_rshift1(u, ndigits); + if (carry) + u[ndigits - 1] |= 0x8000000000000000ull; + } else { + vli_sub(b, b, a, ndigits); + vli_rshift1(b, ndigits); + + if (vli_cmp(v, u, ndigits) < 0) + vli_add(v, v, mod, ndigits); + + vli_sub(v, v, u, ndigits); + if (!EVEN(v)) + carry = vli_add(v, v, mod, ndigits); + + vli_rshift1(v, ndigits); + if (carry) + v[ndigits - 1] |= 0x8000000000000000ull; + } + } + + vli_set(result, u, ndigits); +} +EXPORT_SYMBOL(vli_mod_inv); + +/* ------ Point operations ------ */ + +/* Returns true if p_point is the point at infinity, false otherwise. */ +bool ecc_point_is_zero(const struct ecc_point *point) +{ + return (vli_is_zero(point->x, point->ndigits) && + vli_is_zero(point->y, point->ndigits)); +} +EXPORT_SYMBOL(ecc_point_is_zero); + +/* Point multiplication algorithm using Montgomery's ladder with co-Z + * coordinates. From https://eprint.iacr.org/2011/338.pdf + */ + +/* Double in place */ +static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, + const struct ecc_curve *curve) +{ + /* t1 = x, t2 = y, t3 = z */ + u64 t4[ECC_MAX_DIGITS]; + u64 t5[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; + + if (vli_is_zero(z1, ndigits)) + return; + + /* t4 = y1^2 */ + vli_mod_square_fast(t4, y1, curve); + /* t5 = x1*y1^2 = A */ + vli_mod_mult_fast(t5, x1, t4, curve); + /* t4 = y1^4 */ + vli_mod_square_fast(t4, t4, curve); + /* t2 = y1*z1 = z3 */ + vli_mod_mult_fast(y1, y1, z1, curve); + /* t3 = z1^2 */ + vli_mod_square_fast(z1, z1, curve); + + /* t1 = x1 + z1^2 */ + vli_mod_add(x1, x1, z1, curve_prime, ndigits); + /* t3 = 2*z1^2 */ + vli_mod_add(z1, z1, z1, curve_prime, ndigits); + /* t3 = x1 - z1^2 */ + vli_mod_sub(z1, x1, z1, curve_prime, ndigits); + /* t1 = x1^2 - z1^4 */ + vli_mod_mult_fast(x1, x1, z1, curve); + + /* t3 = 2*(x1^2 - z1^4) */ + vli_mod_add(z1, x1, x1, curve_prime, ndigits); + /* t1 = 3*(x1^2 - z1^4) */ + vli_mod_add(x1, x1, z1, curve_prime, ndigits); + if (vli_test_bit(x1, 0)) { + u64 carry = vli_add(x1, x1, curve_prime, ndigits); + + vli_rshift1(x1, ndigits); + x1[ndigits - 1] |= carry << 63; + } else { + vli_rshift1(x1, ndigits); + } + /* t1 = 3/2*(x1^2 - z1^4) = B */ + + /* t3 = B^2 */ + vli_mod_square_fast(z1, x1, curve); + /* t3 = B^2 - A */ + vli_mod_sub(z1, z1, t5, curve_prime, ndigits); + /* t3 = B^2 - 2A = x3 */ + vli_mod_sub(z1, z1, t5, curve_prime, ndigits); + /* t5 = A - x3 */ + vli_mod_sub(t5, t5, z1, curve_prime, ndigits); + /* t1 = B * (A - x3) */ + vli_mod_mult_fast(x1, x1, t5, curve); + /* t4 = B * (A - x3) - y1^4 = y3 */ + vli_mod_sub(t4, x1, t4, curve_prime, ndigits); + + vli_set(x1, z1, ndigits); + vli_set(z1, y1, ndigits); + vli_set(y1, t4, ndigits); +} + +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ +static void apply_z(u64 *x1, u64 *y1, u64 *z, const struct ecc_curve *curve) +{ + u64 t1[ECC_MAX_DIGITS]; + + vli_mod_square_fast(t1, z, curve); /* z^2 */ + vli_mod_mult_fast(x1, x1, t1, curve); /* x1 * z^2 */ + vli_mod_mult_fast(t1, t1, z, curve); /* z^3 */ + vli_mod_mult_fast(y1, y1, t1, curve); /* y1 * z^3 */ +} + +/* P = (x1, y1) => 2P, (x2, y2) => P' */ +static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + u64 *p_initial_z, const struct ecc_curve *curve) +{ + u64 z[ECC_MAX_DIGITS]; + const unsigned int ndigits = curve->g.ndigits; + + vli_set(x2, x1, ndigits); + vli_set(y2, y1, ndigits); + + vli_clear(z, ndigits); + z[0] = 1; + + if (p_initial_z) + vli_set(z, p_initial_z, ndigits); + + apply_z(x1, y1, z, curve); + + ecc_point_double_jacobian(x1, y1, z, curve); + + apply_z(x2, y2, z, curve); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) + * or P => P', Q => P + Q + */ +static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + const struct ecc_curve *curve) +{ + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + u64 t5[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; + + /* t5 = x2 - x1 */ + vli_mod_sub(t5, x2, x1, curve_prime, ndigits); + /* t5 = (x2 - x1)^2 = A */ + vli_mod_square_fast(t5, t5, curve); + /* t1 = x1*A = B */ + vli_mod_mult_fast(x1, x1, t5, curve); + /* t3 = x2*A = C */ + vli_mod_mult_fast(x2, x2, t5, curve); + /* t4 = y2 - y1 */ + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + /* t5 = (y2 - y1)^2 = D */ + vli_mod_square_fast(t5, y2, curve); + + /* t5 = D - B */ + vli_mod_sub(t5, t5, x1, curve_prime, ndigits); + /* t5 = D - B - C = x3 */ + vli_mod_sub(t5, t5, x2, curve_prime, ndigits); + /* t3 = C - B */ + vli_mod_sub(x2, x2, x1, curve_prime, ndigits); + /* t2 = y1*(C - B) */ + vli_mod_mult_fast(y1, y1, x2, curve); + /* t3 = B - x3 */ + vli_mod_sub(x2, x1, t5, curve_prime, ndigits); + /* t4 = (y2 - y1)*(B - x3) */ + vli_mod_mult_fast(y2, y2, x2, curve); + /* t4 = y3 */ + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + + vli_set(x2, t5, ndigits); +} + +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) + * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) + * or P => P - Q, Q => P + Q + */ +static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, + const struct ecc_curve *curve) +{ + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ + u64 t5[ECC_MAX_DIGITS]; + u64 t6[ECC_MAX_DIGITS]; + u64 t7[ECC_MAX_DIGITS]; + const u64 *curve_prime = curve->p; + const unsigned int ndigits = curve->g.ndigits; + + /* t5 = x2 - x1 */ + vli_mod_sub(t5, x2, x1, curve_prime, ndigits); + /* t5 = (x2 - x1)^2 = A */ + vli_mod_square_fast(t5, t5, curve); + /* t1 = x1*A = B */ + vli_mod_mult_fast(x1, x1, t5, curve); + /* t3 = x2*A = C */ + vli_mod_mult_fast(x2, x2, t5, curve); + /* t4 = y2 + y1 */ + vli_mod_add(t5, y2, y1, curve_prime, ndigits); + /* t4 = y2 - y1 */ + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + + /* t6 = C - B */ + vli_mod_sub(t6, x2, x1, curve_prime, ndigits); + /* t2 = y1 * (C - B) */ + vli_mod_mult_fast(y1, y1, t6, curve); + /* t6 = B + C */ + vli_mod_add(t6, x1, x2, curve_prime, ndigits); + /* t3 = (y2 - y1)^2 */ + vli_mod_square_fast(x2, y2, curve); + /* t3 = x3 */ + vli_mod_sub(x2, x2, t6, curve_prime, ndigits); + + /* t7 = B - x3 */ + vli_mod_sub(t7, x1, x2, curve_prime, ndigits); + /* t4 = (y2 - y1)*(B - x3) */ + vli_mod_mult_fast(y2, y2, t7, curve); + /* t4 = y3 */ + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); + + /* t7 = (y2 + y1)^2 = F */ + vli_mod_square_fast(t7, t5, curve); + /* t7 = x3' */ + vli_mod_sub(t7, t7, t6, curve_prime, ndigits); + /* t6 = x3' - B */ + vli_mod_sub(t6, t7, x1, curve_prime, ndigits); + /* t6 = (y2 + y1)*(x3' - B) */ + vli_mod_mult_fast(t6, t6, t5, curve); + /* t2 = y3' */ + vli_mod_sub(y1, t6, y1, curve_prime, ndigits); + + vli_set(x1, t7, ndigits); +} + +static void ecc_point_mult(struct ecc_point *result, + const struct ecc_point *point, const u64 *scalar, + u64 *initial_z, const struct ecc_curve *curve, + unsigned int ndigits) +{ + /* R0 and R1 */ + u64 rx[2][ECC_MAX_DIGITS]; + u64 ry[2][ECC_MAX_DIGITS]; + u64 z[ECC_MAX_DIGITS]; + u64 sk[2][ECC_MAX_DIGITS]; + u64 *curve_prime = curve->p; + int i, nb; + int num_bits; + int carry; + + carry = vli_add(sk[0], scalar, curve->n, ndigits); + vli_add(sk[1], sk[0], curve->n, ndigits); + scalar = sk[!carry]; + if (curve->nbits == 521) /* NIST P521 */ + num_bits = curve->nbits + 2; + else + num_bits = sizeof(u64) * ndigits * 8 + 1; + + vli_set(rx[1], point->x, ndigits); + vli_set(ry[1], point->y, ndigits); + + xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve); + + for (i = num_bits - 2; i > 0; i--) { + nb = !vli_test_bit(scalar, i); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); + } + + nb = !vli_test_bit(scalar, 0); + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); + + /* Find final 1/Z value. */ + /* X1 - X0 */ + vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits); + /* Yb * (X1 - X0) */ + vli_mod_mult_fast(z, z, ry[1 - nb], curve); + /* xP * Yb * (X1 - X0) */ + vli_mod_mult_fast(z, z, point->x, curve); + + /* 1 / (xP * Yb * (X1 - X0)) */ + vli_mod_inv(z, z, curve_prime, point->ndigits); + + /* yP / (xP * Yb * (X1 - X0)) */ + vli_mod_mult_fast(z, z, point->y, curve); + /* Xb * yP / (xP * Yb * (X1 - X0)) */ + vli_mod_mult_fast(z, z, rx[1 - nb], curve); + /* End 1/Z calculation */ + + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); + + apply_z(rx[0], ry[0], z, curve); + + vli_set(result->x, rx[0], ndigits); + vli_set(result->y, ry[0], ndigits); +} + +/* Computes R = P + Q mod p */ +static void ecc_point_add(const struct ecc_point *result, + const struct ecc_point *p, const struct ecc_point *q, + const struct ecc_curve *curve) +{ + u64 z[ECC_MAX_DIGITS]; + u64 px[ECC_MAX_DIGITS]; + u64 py[ECC_MAX_DIGITS]; + unsigned int ndigits = curve->g.ndigits; + + vli_set(result->x, q->x, ndigits); + vli_set(result->y, q->y, ndigits); + vli_mod_sub(z, result->x, p->x, curve->p, ndigits); + vli_set(px, p->x, ndigits); + vli_set(py, p->y, ndigits); + xycz_add(px, py, result->x, result->y, curve); + vli_mod_inv(z, z, curve->p, ndigits); + apply_z(result->x, result->y, z, curve); +} + +/* Computes R = u1P + u2Q mod p using Shamir's trick. + * Based on: Kenneth MacKay's micro-ecc (2014). + */ +void ecc_point_mult_shamir(const struct ecc_point *result, + const u64 *u1, const struct ecc_point *p, + const u64 *u2, const struct ecc_point *q, + const struct ecc_curve *curve) +{ + u64 z[ECC_MAX_DIGITS]; + u64 sump[2][ECC_MAX_DIGITS]; + u64 *rx = result->x; + u64 *ry = result->y; + unsigned int ndigits = curve->g.ndigits; + unsigned int num_bits; + struct ecc_point sum = ECC_POINT_INIT(sump[0], sump[1], ndigits); + const struct ecc_point *points[4]; + const struct ecc_point *point; + unsigned int idx; + int i; + + ecc_point_add(&sum, p, q, curve); + points[0] = NULL; + points[1] = p; + points[2] = q; + points[3] = ∑ + + num_bits = max(vli_num_bits(u1, ndigits), vli_num_bits(u2, ndigits)); + i = num_bits - 1; + idx = !!vli_test_bit(u1, i); + idx |= (!!vli_test_bit(u2, i)) << 1; + point = points[idx]; + + vli_set(rx, point->x, ndigits); + vli_set(ry, point->y, ndigits); + vli_clear(z + 1, ndigits - 1); + z[0] = 1; + + for (--i; i >= 0; i--) { + ecc_point_double_jacobian(rx, ry, z, curve); + idx = !!vli_test_bit(u1, i); + idx |= (!!vli_test_bit(u2, i)) << 1; + point = points[idx]; + if (point) { + u64 tx[ECC_MAX_DIGITS]; + u64 ty[ECC_MAX_DIGITS]; + u64 tz[ECC_MAX_DIGITS]; + + vli_set(tx, point->x, ndigits); + vli_set(ty, point->y, ndigits); + apply_z(tx, ty, z, curve); + vli_mod_sub(tz, rx, tx, curve->p, ndigits); + xycz_add(tx, ty, rx, ry, curve); + vli_mod_mult_fast(z, z, tz, curve); + } + } + vli_mod_inv(z, z, curve->p, ndigits); + apply_z(rx, ry, z, curve); +} +EXPORT_SYMBOL(ecc_point_mult_shamir); + +/* + * This function performs checks equivalent to Appendix A.4.2 of FIPS 186-5. + * Whereas A.4.2 results in an integer in the interval [1, n-1], this function + * ensures that the integer is in the range of [2, n-3]. We are slightly + * stricter because of the currently used scalar multiplication algorithm. + */ +static int __ecc_is_key_valid(const struct ecc_curve *curve, + const u64 *private_key, unsigned int ndigits) +{ + u64 one[ECC_MAX_DIGITS] = { 1, }; + u64 res[ECC_MAX_DIGITS]; + + if (!private_key) + return -EINVAL; + + if (curve->g.ndigits != ndigits) + return -EINVAL; + + /* Make sure the private key is in the range [2, n-3]. */ + if (vli_cmp(one, private_key, ndigits) != -1) + return -EINVAL; + vli_sub(res, curve->n, one, ndigits); + vli_sub(res, res, one, ndigits); + if (vli_cmp(res, private_key, ndigits) != 1) + return -EINVAL; + + return 0; +} + +int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits, + const u64 *private_key, unsigned int private_key_len) +{ + int nbytes; + const struct ecc_curve *curve = ecc_get_curve(curve_id); + + nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT; + + if (private_key_len != nbytes) + return -EINVAL; + + return __ecc_is_key_valid(curve, private_key, ndigits); +} +EXPORT_SYMBOL(ecc_is_key_valid); + +int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits, + const u64 *private_key, u64 *public_key) +{ + int ret = 0; + struct ecc_point *pk; + const struct ecc_curve *curve = ecc_get_curve(curve_id); + + if (!private_key) { + ret = -EINVAL; + goto out; + } + + pk = ecc_alloc_point(ndigits); + if (!pk) { + ret = -ENOMEM; + goto out; + } + + ecc_point_mult(pk, &curve->g, private_key, NULL, curve, ndigits); + + /* 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; + } + + ecc_swap_digits(pk->x, public_key, ndigits); + ecc_swap_digits(pk->y, &public_key[ndigits], ndigits); + +err_free_point: + ecc_free_point(pk); +out: + return ret; +} +EXPORT_SYMBOL(ecc_make_pub_key); + +/* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */ +int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, + struct ecc_point *pk) +{ + u64 yy[ECC_MAX_DIGITS], xxx[ECC_MAX_DIGITS], w[ECC_MAX_DIGITS]; + + if (WARN_ON(pk->ndigits != curve->g.ndigits)) + return -EINVAL; + + /* Check 1: Verify key is not the zero point. */ + if (ecc_point_is_zero(pk)) + return -EINVAL; + + /* Check 2: Verify key is in the range [1, p-1]. */ + if (vli_cmp(curve->p, pk->x, pk->ndigits) != 1) + return -EINVAL; + if (vli_cmp(curve->p, pk->y, pk->ndigits) != 1) + return -EINVAL; + + /* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */ + vli_mod_square_fast(yy, pk->y, curve); /* y^2 */ + vli_mod_square_fast(xxx, pk->x, curve); /* x^2 */ + vli_mod_mult_fast(xxx, xxx, pk->x, curve); /* x^3 */ + vli_mod_mult_fast(w, curve->a, pk->x, curve); /* a·x */ + vli_mod_add(w, w, curve->b, curve->p, pk->ndigits); /* a·x + b */ + vli_mod_add(w, w, xxx, curve->p, pk->ndigits); /* x^3 + a·x + b */ + if (vli_cmp(yy, w, pk->ndigits) != 0) /* Equation */ + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(ecc_is_pubkey_valid_partial); + +/* SP800-56A section 5.6.2.3.3 full verification */ +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) +{ + int ret = 0; + struct ecc_point *product, *pk; + u64 rand_z[ECC_MAX_DIGITS]; + unsigned int nbytes; + const struct ecc_curve *curve = ecc_get_curve(curve_id); + + if (!private_key || !public_key || ndigits > ARRAY_SIZE(rand_z)) { + ret = -EINVAL; + goto out; + } + + nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT; + + get_random_bytes(rand_z, nbytes); + + pk = ecc_alloc_point(ndigits); + if (!pk) { + ret = -ENOMEM; + goto out; + } + + ecc_swap_digits(public_key, pk->x, ndigits); + ecc_swap_digits(&public_key[ndigits], pk->y, ndigits); + ret = ecc_is_pubkey_valid_partial(curve, pk); + if (ret) + goto err_alloc_product; + + product = ecc_alloc_point(ndigits); + if (!product) { + ret = -ENOMEM; + goto err_alloc_product; + } + + ecc_point_mult(product, pk, private_key, rand_z, curve, ndigits); + + if (ecc_point_is_zero(product)) { + ret = -EFAULT; + goto err_validity; + } + + ecc_swap_digits(product->x, secret, ndigits); + +err_validity: + memzero_explicit(rand_z, sizeof(rand_z)); + ecc_free_point(product); +err_alloc_product: + ecc_free_point(pk); +out: + return ret; +} +EXPORT_SYMBOL(crypto_ecdh_shared_secret); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h new file mode 100644 index 0000000000..0ecade7d02 --- /dev/null +++ b/crypto/ecc_curve_defs.h @@ -0,0 +1,155 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CRYTO_ECC_CURVE_DEFS_H +#define _CRYTO_ECC_CURVE_DEFS_H + +/* NIST P-192: a = p - 3 */ +static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, + 0x188DA80EB03090F6ull }; +static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, + 0x07192B95FFC8DA78ull }; +static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull, + 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull, + 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p192_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFFFFFFFFFEull, + 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p192_b[] = { 0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull, + 0x64210519E59C80E7ull }; +static struct ecc_curve nist_p192 = { + .name = "nist_192", + .nbits = 192, + .g = { + .x = nist_p192_g_x, + .y = nist_p192_g_y, + .ndigits = 3, + }, + .p = nist_p192_p, + .n = nist_p192_n, + .a = nist_p192_a, + .b = nist_p192_b +}; + +/* NIST P-256: a = p - 3 */ +static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, + 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull }; +static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, + 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull }; +static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, + 0x0000000000000000ull, 0xFFFFFFFF00000001ull }; +static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }; +static u64 nist_p256_a[] = { 0xFFFFFFFFFFFFFFFCull, 0x00000000FFFFFFFFull, + 0x0000000000000000ull, 0xFFFFFFFF00000001ull }; +static u64 nist_p256_b[] = { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, + 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull }; +static struct ecc_curve nist_p256 = { + .name = "nist_256", + .nbits = 256, + .g = { + .x = nist_p256_g_x, + .y = nist_p256_g_y, + .ndigits = 4, + }, + .p = nist_p256_p, + .n = nist_p256_n, + .a = nist_p256_a, + .b = nist_p256_b +}; + +/* NIST P-384 */ +static u64 nist_p384_g_x[] = { 0x3A545E3872760AB7ull, 0x5502F25DBF55296Cull, + 0x59F741E082542A38ull, 0x6E1D3B628BA79B98ull, + 0x8Eb1C71EF320AD74ull, 0xAA87CA22BE8B0537ull }; +static u64 nist_p384_g_y[] = { 0x7A431D7C90EA0E5Full, 0x0A60B1CE1D7E819Dull, + 0xE9DA3113B5F0B8C0ull, 0xF8F41DBD289A147Cull, + 0x5D9E98BF9292DC29ull, 0x3617DE4A96262C6Full }; +static u64 nist_p384_p[] = { 0x00000000FFFFFFFFull, 0xFFFFFFFF00000000ull, + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_n[] = { 0xECEC196ACCC52973ull, 0x581A0DB248B0A77Aull, + 0xC7634D81F4372DDFull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_a[] = { 0x00000000FFFFFFFCull, 0xFFFFFFFF00000000ull, + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; +static u64 nist_p384_b[] = { 0x2a85c8edd3ec2aefull, 0xc656398d8a2ed19dull, + 0x0314088f5013875aull, 0x181d9c6efe814112ull, + 0x988e056be3f82d19ull, 0xb3312fa7e23ee7e4ull }; +static struct ecc_curve nist_p384 = { + .name = "nist_384", + .nbits = 384, + .g = { + .x = nist_p384_g_x, + .y = nist_p384_g_y, + .ndigits = 6, + }, + .p = nist_p384_p, + .n = nist_p384_n, + .a = nist_p384_a, + .b = nist_p384_b +}; + +/* NIST P-521 */ +static u64 nist_p521_g_x[] = { 0xf97e7e31c2e5bd66ull, 0x3348b3c1856a429bull, + 0xfe1dc127a2ffa8deull, 0xa14b5e77efe75928ull, + 0xf828af606b4d3dbaull, 0x9c648139053fb521ull, + 0x9e3ecb662395b442ull, 0x858e06b70404e9cdull, + 0xc6ull }; +static u64 nist_p521_g_y[] = { 0x88be94769fd16650ull, 0x353c7086a272c240ull, + 0xc550b9013fad0761ull, 0x97ee72995ef42640ull, + 0x17afbd17273e662cull, 0x98f54449579b4468ull, + 0x5c8a5fb42c7d1bd9ull, 0x39296a789a3bc004ull, + 0x118ull }; +static u64 nist_p521_p[] = { 0xffffffffffffffffull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0x1ffull }; +static u64 nist_p521_n[] = { 0xbb6fb71e91386409ull, 0x3bb5c9b8899c47aeull, + 0x7fcc0148f709a5d0ull, 0x51868783bf2f966bull, + 0xfffffffffffffffaull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0x1ffull }; +static u64 nist_p521_a[] = { 0xfffffffffffffffcull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0xffffffffffffffffull, 0xffffffffffffffffull, + 0x1ffull }; +static u64 nist_p521_b[] = { 0xef451fd46b503f00ull, 0x3573df883d2c34f1ull, + 0x1652c0bd3bb1bf07ull, 0x56193951ec7e937bull, + 0xb8b489918ef109e1ull, 0xa2da725b99b315f3ull, + 0x929a21a0b68540eeull, 0x953eb9618e1c9a1full, + 0x051ull }; +static struct ecc_curve nist_p521 = { + .name = "nist_521", + .nbits = 521, + .g = { + .x = nist_p521_g_x, + .y = nist_p521_g_y, + .ndigits = 9, + }, + .p = nist_p521_p, + .n = nist_p521_n, + .a = nist_p521_a, + .b = nist_p521_b +}; + +/* curve25519 */ +static u64 curve25519_g_x[] = { 0x0000000000000009, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000 }; +static u64 curve25519_p[] = { 0xffffffffffffffed, 0xffffffffffffffff, + 0xffffffffffffffff, 0x7fffffffffffffff }; +static u64 curve25519_a[] = { 0x000000000001DB41, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000 }; +static const struct ecc_curve ecc_25519 = { + .name = "curve25519", + .nbits = 255, + .g = { + .x = curve25519_g_x, + .ndigits = 4, + }, + .p = curve25519_p, + .a = curve25519_a, +}; + +#endif diff --git a/include/crypto/ecc_curve.h b/include/crypto/ecc_curve.h new file mode 100644 index 0000000000..7d90c5e822 --- /dev/null +++ b/include/crypto/ecc_curve.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2021 HiSilicon */ + +#ifndef _CRYTO_ECC_CURVE_H +#define _CRYTO_ECC_CURVE_H + +#include <linux/types.h> + +/** + * struct ecc_point - elliptic curve point in affine coordinates + * + * @x: X coordinate in vli form. + * @y: Y coordinate in vli form. + * @ndigits: Length of vlis in u64 qwords. + */ +struct ecc_point { + u64 *x; + u64 *y; + u8 ndigits; +}; + +/** + * struct ecc_curve - definition of elliptic curve + * + * @name: Short name of the curve. + * @nbits: The number of bits of a curve. + * @g: Generator point of the curve. + * @p: Prime number, if Barrett's reduction is used for this curve + * pre-calculated value 'mu' is appended to the @p after ndigits. + * Use of Barrett's reduction is heuristically determined in + * vli_mmod_fast(). + * @n: Order of the curve group. + * @a: Curve parameter a. + * @b: Curve parameter b. + */ +struct ecc_curve { + char *name; + u32 nbits; + struct ecc_point g; + u64 *p; + u64 *n; + u64 *a; + u64 *b; +}; + +/** + * ecc_get_curve() - get elliptic curve; + * @curve_id: Curves IDs: + * defined in 'include/crypto/ecdh.h'; + * + * Returns curve if get curve succssful, NULL otherwise + */ +const struct ecc_curve *ecc_get_curve(unsigned int curve_id); + +/** + * ecc_get_curve25519() - get curve25519 curve; + * + * Returns curve25519 + */ +const struct ecc_curve *ecc_get_curve25519(void); + +#endif diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h new file mode 100644 index 0000000000..9784ecdd2f --- /dev/null +++ b/include/crypto/ecdh.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * ECDH params to be used with kpp API + * + * Copyright (c) 2016, Intel Corporation + * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com> + */ +#ifndef _CRYPTO_ECDH_ +#define _CRYPTO_ECDH_ + +/** + * DOC: ECDH Helper Functions + * + * To use ECDH with the KPP cipher API, the following data structure and + * functions should be used. + * + * The ECC curves known to the ECDH implementation are specified in this + * header file. + * + * To use ECDH with KPP, the following functions should be used to operate on + * an ECDH private key. The packet private key that can be set with + * the KPP API function call of crypto_kpp_set_secret. + */ + +/* Curves IDs */ +#define ECC_CURVE_NIST_P192 0x0001 +#define ECC_CURVE_NIST_P256 0x0002 +#define ECC_CURVE_NIST_P384 0x0003 +#define ECC_CURVE_NIST_P521 0x0004 + +/** + * struct ecdh - define an ECDH private key + * + * @key: Private ECDH key + * @key_size: Size of the private ECDH key + */ +struct ecdh { + char *key; + unsigned short key_size; +}; + +/** + * crypto_ecdh_key_len() - Obtain the size of the private ECDH key + * @params: private ECDH key + * + * This function returns the packet ECDH key size. A caller can use that + * with the provided ECDH private key reference to obtain the required + * memory size to hold a packet key. + * + * Return: size of the key in bytes + */ +unsigned int crypto_ecdh_key_len(const struct ecdh *params); + +/** + * crypto_ecdh_encode_key() - encode the private key + * @buf: Buffer allocated by the caller to hold the packet ECDH + * private key. The buffer should be at least crypto_ecdh_key_len + * bytes in size. + * @len: Length of the packet private key buffer + * @p: Buffer with the caller-specified private key + * + * The ECDH implementations operate on a packet representation of the private + * key. + * + * Return: -EINVAL if buffer has insufficient size, 0 on success + */ +int crypto_ecdh_encode_key(char *buf, unsigned int len, const struct ecdh *p); + +/** + * crypto_ecdh_decode_key() - decode a private key + * @buf: Buffer holding a packet key that should be decoded + * @len: Length of the packet private key buffer + * @p: Buffer allocated by the caller that is filled with the + * unpacked ECDH private key. + * + * The unpacking obtains the private key by pointing @p to the correct location + * in @buf. Thus, both pointers refer to the same memory. + * + * Return: -EINVAL if buffer has insufficient size, 0 on success + */ +int crypto_ecdh_decode_key(const char *buf, unsigned int len, struct ecdh *p); + +#endif diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h new file mode 100644 index 0000000000..f191491cc0 --- /dev/null +++ b/include/crypto/internal/ecc.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2013, Kenneth MacKay + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _CRYPTO_ECC_H +#define _CRYPTO_ECC_H + +#include <crypto/ecc_curve.h> +#include <asm/unaligned.h> + +/* One digit is u64 qword. */ +#define ECC_CURVE_NIST_P192_DIGITS 3 +#define ECC_CURVE_NIST_P256_DIGITS 4 +#define ECC_CURVE_NIST_P384_DIGITS 6 +#define ECC_CURVE_NIST_P521_DIGITS 9 +#define ECC_MAX_DIGITS DIV_ROUND_UP(521, 64) /* NIST P521 */ + +#define ECC_DIGITS_TO_BYTES_SHIFT 3 + +#define ECC_MAX_BYTES (ECC_MAX_DIGITS << ECC_DIGITS_TO_BYTES_SHIFT) + +#define ECC_POINT_INIT(x, y, ndigits) (struct ecc_point) { x, y, ndigits } + +/** + * ecc_swap_digits() - Copy ndigits from big endian array to native array + * @in: Input array + * @out: Output array + * @ndigits: Number of digits to copy + */ +static inline void ecc_swap_digits(const void *in, u64 *out, unsigned int ndigits) +{ + const __be64 *src = (__force __be64 *)in; + int i; + + for (i = 0; i < ndigits; i++) + out[i] = get_unaligned_be64(&src[ndigits - 1 - i]); +} + +/** + * ecc_digits_from_bytes() - Create ndigits-sized digits array from byte array + * @in: Input byte array + * @nbytes Size of input byte array + * @out Output digits array + * @ndigits: Number of digits to create from byte array + */ +void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes, + u64 *out, unsigned int ndigits); + +/** + * ecc_is_key_valid() - Validate a given ECDH private key + * + * @curve_id: id representing the curve to use + * @ndigits: curve's number of digits + * @private_key: private key to be used for the given curve + * @private_key_len: private key length + * + * Returns 0 if the key is acceptable, a negative value otherwise + */ +int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits, + const u64 *private_key, unsigned int private_key_len); + +/** + * ecc_make_pub_key() - Compute an ECC public key + * + * @curve_id: id representing the curve to use + * @ndigits: curve's number of digits + * @private_key: pregenerated private key for the given curve + * @public_key: buffer for storing the generated public key + * + * Returns 0 if the public key was generated successfully, a negative value + * if an error occurred. + */ +int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits, + const u64 *private_key, u64 *public_key); + +/** + * crypto_ecdh_shared_secret() - Compute a shared secret + * + * @curve_id: id representing the curve to use + * @ndigits: curve's number of digits + * @private_key: private key of part A + * @public_key: public key of counterpart B + * @secret: buffer for storing the calculated shared secret + * + * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret + * before using it for symmetric encryption or HMAC. + * + * Returns 0 if the shared secret was generated successfully, a negative value + * if an error occurred. + */ +int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, + const u64 *private_key, const u64 *public_key, + u64 *secret); + +/** + * ecc_is_pubkey_valid_partial() - Partial public key validation + * + * @curve: elliptic curve domain parameters + * @pk: public key as a point + * + * Valdiate public key according to SP800-56A section 5.6.2.3.4 ECC Partial + * Public-Key Validation Routine. + * + * Note: There is no check that the public key is in the correct elliptic curve + * subgroup. + * + * Return: 0 if validation is successful, -EINVAL if validation is failed. + */ +int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, + struct ecc_point *pk); + +/** + * ecc_is_pubkey_valid_full() - Full public key validation + * + * @curve: elliptic curve domain parameters + * @pk: public key as a point + * + * Valdiate public key according to SP800-56A section 5.6.2.3.3 ECC Full + * Public-Key Validation Routine. + * + * Return: 0 if validation is successful, -EINVAL if validation is failed. + */ +int ecc_is_pubkey_valid_full(const struct ecc_curve *curve, + struct ecc_point *pk); + +/** + * vli_is_zero() - Determine is vli is zero + * + * @vli: vli to check. + * @ndigits: length of the @vli + */ +bool vli_is_zero(const u64 *vli, unsigned int ndigits); + +/** + * vli_cmp() - compare left and right vlis + * + * @left: vli + * @right: vli + * @ndigits: length of both vlis + * + * Returns sign of @left - @right, i.e. -1 if @left < @right, + * 0 if @left == @right, 1 if @left > @right. + */ +int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits); + +/** + * vli_sub() - Subtracts right from left + * + * @result: where to write result + * @left: vli + * @right vli + * @ndigits: length of all vlis + * + * Note: can modify in-place. + * + * Return: carry bit. + */ +u64 vli_sub(u64 *result, const u64 *left, const u64 *right, + unsigned int ndigits); + +/** + * vli_from_be64() - Load vli from big-endian u64 array + * + * @dest: destination vli + * @src: source array of u64 BE values + * @ndigits: length of both vli and array + */ +void vli_from_be64(u64 *dest, const void *src, unsigned int ndigits); + +/** + * vli_from_le64() - Load vli from little-endian u64 array + * + * @dest: destination vli + * @src: source array of u64 LE values + * @ndigits: length of both vli and array + */ +void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits); + +/** + * vli_mod_inv() - Modular inversion + * + * @result: where to write vli number + * @input: vli value to operate on + * @mod: modulus + * @ndigits: length of all vlis + */ +void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod, + unsigned int ndigits); + +/** + * vli_mod_mult_slow() - Modular multiplication + * + * @result: where to write result value + * @left: vli number to multiply with @right + * @right: vli number to multiply with @left + * @mod: modulus + * @ndigits: length of all vlis + * + * Note: Assumes that mod is big enough curve order. + */ +void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right, + const u64 *mod, unsigned int ndigits); + +/** + * vli_num_bits() - Counts the number of bits required for vli. + * + * @vli: vli to check. + * @ndigits: Length of the @vli + * + * Return: The number of bits required to represent @vli. + */ +unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits); + +/** + * ecc_aloc_point() - Allocate ECC point. + * + * @ndigits: Length of vlis in u64 qwords. + * + * Return: Pointer to the allocated point or NULL if allocation failed. + */ +struct ecc_point *ecc_alloc_point(unsigned int ndigits); + +/** + * ecc_free_point() - Free ECC point. + * + * @p: The point to free. + */ +void ecc_free_point(struct ecc_point *p); + +/** + * ecc_point_is_zero() - Check if point is zero. + * + * @p: Point to check for zero. + * + * Return: true if point is the point at infinity, false otherwise. + */ +bool ecc_point_is_zero(const struct ecc_point *point); + +/** + * ecc_point_mult_shamir() - Add two points multiplied by scalars + * + * @result: resulting point + * @x: scalar to multiply with @p + * @p: point to multiply with @x + * @y: scalar to multiply with @q + * @q: point to multiply with @y + * @curve: curve + * + * Returns result = x * p + x * q over the curve. + * This works faster than two multiplications and addition. + */ +void ecc_point_mult_shamir(const struct ecc_point *result, + const u64 *x, const struct ecc_point *p, + const u64 *y, const struct ecc_point *q, + const struct ecc_curve *curve); + +#endif -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 16/19] Add elliptic curve cryptography (ECC) helper functions 2024-08-01 5:57 ` [PATCH v2 16/19] Add elliptic curve cryptography (ECC) helper functions Sascha Hauer @ 2024-08-05 11:32 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 11:32 UTC (permalink / raw) To: Sascha Hauer, Barebox List Hello Sascha, On 01.08.24 07:57, Sascha Hauer wrote: > This ports the functions needed for supporting elliptic curve cryptography > (ECC) from the Kernel. The code is taken from Linux-6.10 and mostly > unchanged. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > crypto/Kconfig | 3 + > crypto/Makefile | 1 + > crypto/ecc.c | 1661 +++++++++++++++++++++++++++++++++ > crypto/ecc_curve_defs.h | 155 +++ > include/crypto/ecc_curve.h | 62 ++ > include/crypto/ecdh.h | 83 ++ > include/crypto/internal/ecc.h | 278 ++++++ > 7 files changed, 2243 insertions(+) > create mode 100644 crypto/ecc.c > create mode 100644 crypto/ecc_curve_defs.h > create mode 100644 include/crypto/ecc_curve.h > create mode 100644 include/crypto/ecdh.h > create mode 100644 include/crypto/internal/ecc.h > > diff --git a/crypto/Kconfig b/crypto/Kconfig > index 78b499f646..e953ef5e15 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -153,4 +153,7 @@ config JWT > select BASE64 > select CRYPTO_RSA > > +config CRYPTO_ECC > + bool > + > endmenu > diff --git a/crypto/Makefile b/crypto/Makefile > index e84360a8c7..83c05761de 100644 > --- a/crypto/Makefile > +++ b/crypto/Makefile > @@ -18,6 +18,7 @@ obj-y += memneq.o > obj-$(CONFIG_CRYPTO_PBKDF2) += pbkdf2.o > obj-$(CONFIG_CRYPTO_RSA) += rsa.o > obj-$(CONFIG_CRYPTO_KEYSTORE) += keystore.o > +obj-$(CONFIG_CRYPTO_ECC) += ecc.o > > obj-$(CONFIG_JWT) += jwt.o > > diff --git a/crypto/ecc.c b/crypto/ecc.c > new file mode 100644 > index 0000000000..a0ab962262 > --- /dev/null > +++ b/crypto/ecc.c > @@ -0,0 +1,1661 @@ > +/* > + * Copyright (c) 2013, 2014 Kenneth MacKay. All rights reserved. > + * Copyright (c) 2019 Vitaly Chikunov <vt@altlinux.org> > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are > + * met: > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + */ > + > +#include <common.h> > +#include <stdlib.h> > +#include <crypto/ecc_curve.h> > +#include <crypto/ecdh.h> > +#include <crypto/internal/ecc.h> > +#include <asm/unaligned.h> > + > +#include "ecc_curve_defs.h" > + > +typedef struct { > + u64 m_low; > + u64 m_high; > +} uint128_t; > + > +/* Returns curv25519 curve param */ > +const struct ecc_curve *ecc_get_curve25519(void) > +{ > + return &ecc_25519; > +} > +EXPORT_SYMBOL(ecc_get_curve25519); > + > +const struct ecc_curve *ecc_get_curve(unsigned int curve_id) > +{ > + switch (curve_id) { > + case ECC_CURVE_NIST_P192: > + return &nist_p192; > + case ECC_CURVE_NIST_P256: > + return &nist_p256; > + case ECC_CURVE_NIST_P384: > + return &nist_p384; > + case ECC_CURVE_NIST_P521: > + return &nist_p521; > + default: > + return NULL; > + } > +} > +EXPORT_SYMBOL(ecc_get_curve); > + > +void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes, > + u64 *out, unsigned int ndigits) > +{ > + int diff = ndigits - DIV_ROUND_UP(nbytes, sizeof(u64)); > + unsigned int o = nbytes & 7; > + __be64 msd = 0; > + > + /* diff > 0: not enough input bytes: set most significant digits to 0 */ > + if (diff > 0) { > + ndigits -= diff; > + memset(&out[ndigits - 1], 0, diff * sizeof(u64)); > + } > + > + if (o) { > + memcpy((u8 *)&msd + sizeof(msd) - o, in, o); > + out[--ndigits] = be64_to_cpu(msd); > + in += o; > + } > + ecc_swap_digits(in, out, ndigits); > +} > +EXPORT_SYMBOL(ecc_digits_from_bytes); > + > +static u64 *ecc_alloc_digits_space(unsigned int ndigits) > +{ > + size_t len = ndigits * sizeof(u64); > + > + if (!len) > + return NULL; > + > + return kmalloc(len, GFP_KERNEL); > +} > + > +static void ecc_free_digits_space(u64 *space) > +{ > + kfree_sensitive(space); > +} > + > +struct ecc_point *ecc_alloc_point(unsigned int ndigits) > +{ > + struct ecc_point *p = kmalloc(sizeof(*p), GFP_KERNEL); > + > + if (!p) > + return NULL; > + > + p->x = ecc_alloc_digits_space(ndigits); > + if (!p->x) > + goto err_alloc_x; > + > + p->y = ecc_alloc_digits_space(ndigits); > + if (!p->y) > + goto err_alloc_y; > + > + p->ndigits = ndigits; > + > + return p; > + > +err_alloc_y: > + ecc_free_digits_space(p->x); > +err_alloc_x: > + kfree(p); > + return NULL; > +} > +EXPORT_SYMBOL(ecc_alloc_point); > + > +void ecc_free_point(struct ecc_point *p) > +{ > + if (!p) > + return; > + > + kfree_sensitive(p->x); > + kfree_sensitive(p->y); > + kfree_sensitive(p); > +} > +EXPORT_SYMBOL(ecc_free_point); > + > +static void vli_clear(u64 *vli, unsigned int ndigits) > +{ > + int i; > + > + for (i = 0; i < ndigits; i++) > + vli[i] = 0; > +} > + > +/* Returns true if vli == 0, false otherwise. */ > +bool vli_is_zero(const u64 *vli, unsigned int ndigits) > +{ > + int i; > + > + for (i = 0; i < ndigits; i++) { > + if (vli[i]) > + return false; > + } > + > + return true; > +} > +EXPORT_SYMBOL(vli_is_zero); > + > +/* Returns nonzero if bit of vli is set. */ > +static u64 vli_test_bit(const u64 *vli, unsigned int bit) > +{ > + return (vli[bit / 64] & ((u64)1 << (bit % 64))); > +} > + > +static bool vli_is_negative(const u64 *vli, unsigned int ndigits) > +{ > + return vli_test_bit(vli, ndigits * 64 - 1); > +} > + > +/* Counts the number of 64-bit "digits" in vli. */ > +static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits) > +{ > + int i; > + > + /* Search from the end until we find a non-zero digit. > + * We do it in reverse because we expect that most digits will > + * be nonzero. > + */ > + for (i = ndigits - 1; i >= 0 && vli[i] == 0; i--); > + > + return (i + 1); > +} > + > +/* Counts the number of bits required for vli. */ > +unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits) > +{ > + unsigned int i, num_digits; > + u64 digit; > + > + num_digits = vli_num_digits(vli, ndigits); > + if (num_digits == 0) > + return 0; > + > + digit = vli[num_digits - 1]; > + for (i = 0; digit; i++) > + digit >>= 1; > + > + return ((num_digits - 1) * 64 + i); > +} > +EXPORT_SYMBOL(vli_num_bits); > + > +/* Set dest from unaligned bit string src. */ > +void vli_from_be64(u64 *dest, const void *src, unsigned int ndigits) > +{ > + int i; > + const u64 *from = src; > + > + for (i = 0; i < ndigits; i++) > + dest[i] = get_unaligned_be64(&from[ndigits - 1 - i]); > +} > +EXPORT_SYMBOL(vli_from_be64); > + > +void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits) > +{ > + int i; > + const u64 *from = src; > + > + for (i = 0; i < ndigits; i++) > + dest[i] = get_unaligned_le64(&from[i]); > +} > +EXPORT_SYMBOL(vli_from_le64); > + > +/* Sets dest = src. */ > +static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits) > +{ > + int i; > + > + for (i = 0; i < ndigits; i++) > + dest[i] = src[i]; > +} > + > +/* Returns sign of left - right. */ > +int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits) > +{ > + int i; > + > + for (i = ndigits - 1; i >= 0; i--) { > + if (left[i] > right[i]) > + return 1; > + else if (left[i] < right[i]) > + return -1; > + } > + > + return 0; > +} > +EXPORT_SYMBOL(vli_cmp); > + > +/* Computes result = in << c, returning carry. Can modify in place > + * (if result == in). 0 < shift < 64. > + */ > +static u64 vli_lshift(u64 *result, const u64 *in, unsigned int shift, > + unsigned int ndigits) > +{ > + u64 carry = 0; > + int i; > + > + for (i = 0; i < ndigits; i++) { > + u64 temp = in[i]; > + > + result[i] = (temp << shift) | carry; > + carry = temp >> (64 - shift); > + } > + > + return carry; > +} > + > +/* Computes vli = vli >> 1. */ > +static void vli_rshift1(u64 *vli, unsigned int ndigits) > +{ > + u64 *end = vli; > + u64 carry = 0; > + > + vli += ndigits; > + > + while (vli-- > end) { > + u64 temp = *vli; > + *vli = (temp >> 1) | carry; > + carry = temp << 63; > + } > +} > + > +/* Computes result = left + right, returning carry. Can modify in place. */ > +static u64 vli_add(u64 *result, const u64 *left, const u64 *right, > + unsigned int ndigits) > +{ > + u64 carry = 0; > + int i; > + > + for (i = 0; i < ndigits; i++) { > + u64 sum; > + > + sum = left[i] + right[i] + carry; > + if (sum != left[i]) > + carry = (sum < left[i]); > + > + result[i] = sum; > + } > + > + return carry; > +} > + > +/* Computes result = left + right, returning carry. Can modify in place. */ > +static u64 vli_uadd(u64 *result, const u64 *left, u64 right, > + unsigned int ndigits) > +{ > + u64 carry = right; > + int i; > + > + for (i = 0; i < ndigits; i++) { > + u64 sum; > + > + sum = left[i] + carry; > + if (sum != left[i]) > + carry = (sum < left[i]); > + else > + carry = !!carry; > + > + result[i] = sum; > + } > + > + return carry; > +} > + > +/* Computes result = left - right, returning borrow. Can modify in place. */ > +u64 vli_sub(u64 *result, const u64 *left, const u64 *right, > + unsigned int ndigits) > +{ > + u64 borrow = 0; > + int i; > + > + for (i = 0; i < ndigits; i++) { > + u64 diff; > + > + diff = left[i] - right[i] - borrow; > + if (diff != left[i]) > + borrow = (diff > left[i]); > + > + result[i] = diff; > + } > + > + return borrow; > +} > +EXPORT_SYMBOL(vli_sub); > + > +/* Computes result = left - right, returning borrow. Can modify in place. */ > +static u64 vli_usub(u64 *result, const u64 *left, u64 right, > + unsigned int ndigits) > +{ > + u64 borrow = right; > + int i; > + > + for (i = 0; i < ndigits; i++) { > + u64 diff; > + > + diff = left[i] - borrow; > + if (diff != left[i]) > + borrow = (diff > left[i]); > + > + result[i] = diff; > + } > + > + return borrow; > +} > + > +static uint128_t mul_64_64(u64 left, u64 right) > +{ > + uint128_t result; > +#if defined(CONFIG_ARCH_SUPPORTS_INT128) > + unsigned __int128 m = (unsigned __int128)left * right; > + > + result.m_low = m; > + result.m_high = m >> 64; > +#else > + u64 a0 = left & 0xffffffffull; > + u64 a1 = left >> 32; > + u64 b0 = right & 0xffffffffull; > + u64 b1 = right >> 32; > + u64 m0 = a0 * b0; > + u64 m1 = a0 * b1; > + u64 m2 = a1 * b0; > + u64 m3 = a1 * b1; > + > + m2 += (m0 >> 32); > + m2 += m1; > + > + /* Overflow */ > + if (m2 < m1) > + m3 += 0x100000000ull; > + > + result.m_low = (m0 & 0xffffffffull) | (m2 << 32); > + result.m_high = m3 + (m2 >> 32); > +#endif > + return result; > +} > + > +static uint128_t add_128_128(uint128_t a, uint128_t b) > +{ > + uint128_t result; > + > + result.m_low = a.m_low + b.m_low; > + result.m_high = a.m_high + b.m_high + (result.m_low < a.m_low); > + > + return result; > +} > + > +static void vli_mult(u64 *result, const u64 *left, const u64 *right, > + unsigned int ndigits) > +{ > + uint128_t r01 = { 0, 0 }; > + u64 r2 = 0; > + unsigned int i, k; > + > + /* Compute each digit of result in sequence, maintaining the > + * carries. > + */ > + for (k = 0; k < ndigits * 2 - 1; k++) { > + unsigned int min; > + > + if (k < ndigits) > + min = 0; > + else > + min = (k + 1) - ndigits; > + > + for (i = min; i <= k && i < ndigits; i++) { > + uint128_t product; > + > + product = mul_64_64(left[i], right[k - i]); > + > + r01 = add_128_128(r01, product); > + r2 += (r01.m_high < product.m_high); > + } > + > + result[k] = r01.m_low; > + r01.m_low = r01.m_high; > + r01.m_high = r2; > + r2 = 0; > + } > + > + result[ndigits * 2 - 1] = r01.m_low; > +} > + > +/* Compute product = left * right, for a small right value. */ > +static void vli_umult(u64 *result, const u64 *left, u32 right, > + unsigned int ndigits) > +{ > + uint128_t r01 = { 0 }; > + unsigned int k; > + > + for (k = 0; k < ndigits; k++) { > + uint128_t product; > + > + product = mul_64_64(left[k], right); > + r01 = add_128_128(r01, product); > + /* no carry */ > + result[k] = r01.m_low; > + r01.m_low = r01.m_high; > + r01.m_high = 0; > + } > + result[k] = r01.m_low; > + for (++k; k < ndigits * 2; k++) > + result[k] = 0; > +} > + > +static void vli_square(u64 *result, const u64 *left, unsigned int ndigits) > +{ > + uint128_t r01 = { 0, 0 }; > + u64 r2 = 0; > + int i, k; > + > + for (k = 0; k < ndigits * 2 - 1; k++) { > + unsigned int min; > + > + if (k < ndigits) > + min = 0; > + else > + min = (k + 1) - ndigits; > + > + for (i = min; i <= k && i <= k - i; i++) { > + uint128_t product; > + > + product = mul_64_64(left[i], left[k - i]); > + > + if (i < k - i) { > + r2 += product.m_high >> 63; > + product.m_high = (product.m_high << 1) | > + (product.m_low >> 63); > + product.m_low <<= 1; > + } > + > + r01 = add_128_128(r01, product); > + r2 += (r01.m_high < product.m_high); > + } > + > + result[k] = r01.m_low; > + r01.m_low = r01.m_high; > + r01.m_high = r2; > + r2 = 0; > + } > + > + result[ndigits * 2 - 1] = r01.m_low; > +} > + > +/* Computes result = (left + right) % mod. > + * Assumes that left < mod and right < mod, result != mod. > + */ > +static void vli_mod_add(u64 *result, const u64 *left, const u64 *right, > + const u64 *mod, unsigned int ndigits) > +{ > + u64 carry; > + > + carry = vli_add(result, left, right, ndigits); > + > + /* result > mod (result = mod + remainder), so subtract mod to > + * get remainder. > + */ > + if (carry || vli_cmp(result, mod, ndigits) >= 0) > + vli_sub(result, result, mod, ndigits); > +} > + > +/* Computes result = (left - right) % mod. > + * Assumes that left < mod and right < mod, result != mod. > + */ > +static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right, > + const u64 *mod, unsigned int ndigits) > +{ > + u64 borrow = vli_sub(result, left, right, ndigits); > + > + /* In this case, p_result == -diff == (max int) - diff. > + * Since -x % d == d - x, we can get the correct result from > + * result + mod (with overflow). > + */ > + if (borrow) > + vli_add(result, result, mod, ndigits); > +} > + > +/* > + * Computes result = product % mod > + * for special form moduli: p = 2^k-c, for small c (note the minus sign) > + * > + * References: > + * R. Crandall, C. Pomerance. Prime Numbers: A Computational Perspective. > + * 9 Fast Algorithms for Large-Integer Arithmetic. 9.2.3 Moduli of special form > + * Algorithm 9.2.13 (Fast mod operation for special-form moduli). > + */ > +static void vli_mmod_special(u64 *result, const u64 *product, > + const u64 *mod, unsigned int ndigits) > +{ > + u64 c = -mod[0]; > + u64 t[ECC_MAX_DIGITS * 2]; > + u64 r[ECC_MAX_DIGITS * 2]; > + > + vli_set(r, product, ndigits * 2); > + while (!vli_is_zero(r + ndigits, ndigits)) { > + vli_umult(t, r + ndigits, c, ndigits); > + vli_clear(r + ndigits, ndigits); > + vli_add(r, r, t, ndigits * 2); > + } > + vli_set(t, mod, ndigits); > + vli_clear(t + ndigits, ndigits); > + while (vli_cmp(r, t, ndigits * 2) >= 0) > + vli_sub(r, r, t, ndigits * 2); > + vli_set(result, r, ndigits); > +} > + > +/* > + * Computes result = product % mod > + * for special form moduli: p = 2^{k-1}+c, for small c (note the plus sign) > + * where k-1 does not fit into qword boundary by -1 bit (such as 255). > + > + * References (loosely based on): > + * A. Menezes, P. van Oorschot, S. Vanstone. Handbook of Applied Cryptography. > + * 14.3.4 Reduction methods for moduli of special form. Algorithm 14.47. > + * URL: http://cacr.uwaterloo.ca/hac/about/chap14.pdf > + * > + * H. Cohen, G. Frey, R. Avanzi, C. Doche, T. Lange, K. Nguyen, F. Vercauteren. > + * Handbook of Elliptic and Hyperelliptic Curve Cryptography. > + * Algorithm 10.25 Fast reduction for special form moduli > + */ > +static void vli_mmod_special2(u64 *result, const u64 *product, > + const u64 *mod, unsigned int ndigits) > +{ > + u64 c2 = mod[0] * 2; > + u64 q[ECC_MAX_DIGITS]; > + u64 r[ECC_MAX_DIGITS * 2]; > + u64 m[ECC_MAX_DIGITS * 2]; /* expanded mod */ > + int carry; /* last bit that doesn't fit into q */ > + int i; > + > + vli_set(m, mod, ndigits); > + vli_clear(m + ndigits, ndigits); > + > + vli_set(r, product, ndigits); > + /* q and carry are top bits */ > + vli_set(q, product + ndigits, ndigits); > + vli_clear(r + ndigits, ndigits); > + carry = vli_is_negative(r, ndigits); > + if (carry) > + r[ndigits - 1] &= (1ull << 63) - 1; > + for (i = 1; carry || !vli_is_zero(q, ndigits); i++) { > + u64 qc[ECC_MAX_DIGITS * 2]; > + > + vli_umult(qc, q, c2, ndigits); > + if (carry) > + vli_uadd(qc, qc, mod[0], ndigits * 2); > + vli_set(q, qc + ndigits, ndigits); > + vli_clear(qc + ndigits, ndigits); > + carry = vli_is_negative(qc, ndigits); > + if (carry) > + qc[ndigits - 1] &= (1ull << 63) - 1; > + if (i & 1) > + vli_sub(r, r, qc, ndigits * 2); > + else > + vli_add(r, r, qc, ndigits * 2); > + } > + while (vli_is_negative(r, ndigits * 2)) > + vli_add(r, r, m, ndigits * 2); > + while (vli_cmp(r, m, ndigits * 2) >= 0) > + vli_sub(r, r, m, ndigits * 2); > + > + vli_set(result, r, ndigits); > +} > + > +/* > + * Computes result = product % mod, where product is 2N words long. > + * Reference: Ken MacKay's micro-ecc. > + * Currently only designed to work for curve_p or curve_n. > + */ > +static void vli_mmod_slow(u64 *result, u64 *product, const u64 *mod, > + unsigned int ndigits) > +{ > + u64 mod_m[2 * ECC_MAX_DIGITS]; > + u64 tmp[2 * ECC_MAX_DIGITS]; > + u64 *v[2] = { tmp, product }; > + u64 carry = 0; > + unsigned int i; > + /* Shift mod so its highest set bit is at the maximum position. */ > + int shift = (ndigits * 2 * 64) - vli_num_bits(mod, ndigits); > + int word_shift = shift / 64; > + int bit_shift = shift % 64; > + > + vli_clear(mod_m, word_shift); > + if (bit_shift > 0) { > + for (i = 0; i < ndigits; ++i) { > + mod_m[word_shift + i] = (mod[i] << bit_shift) | carry; > + carry = mod[i] >> (64 - bit_shift); > + } > + } else > + vli_set(mod_m + word_shift, mod, ndigits); > + > + for (i = 1; shift >= 0; --shift) { > + u64 borrow = 0; > + unsigned int j; > + > + for (j = 0; j < ndigits * 2; ++j) { > + u64 diff = v[i][j] - mod_m[j] - borrow; > + > + if (diff != v[i][j]) > + borrow = (diff > v[i][j]); > + v[1 - i][j] = diff; > + } > + i = !(i ^ borrow); /* Swap the index if there was no borrow */ > + vli_rshift1(mod_m, ndigits); > + mod_m[ndigits - 1] |= mod_m[ndigits] << (64 - 1); > + vli_rshift1(mod_m + ndigits, ndigits); > + } > + vli_set(result, v[i], ndigits); > +} > + > +/* Computes result = product % mod using Barrett's reduction with precomputed > + * value mu appended to the mod after ndigits, mu = (2^{2w} / mod) and have > + * length ndigits + 1, where mu * (2^w - 1) should not overflow ndigits > + * boundary. > + * > + * Reference: > + * R. Brent, P. Zimmermann. Modern Computer Arithmetic. 2010. > + * 2.4.1 Barrett's algorithm. Algorithm 2.5. > + */ > +static void vli_mmod_barrett(u64 *result, u64 *product, const u64 *mod, > + unsigned int ndigits) > +{ > + u64 q[ECC_MAX_DIGITS * 2]; > + u64 r[ECC_MAX_DIGITS * 2]; > + const u64 *mu = mod + ndigits; > + > + vli_mult(q, product + ndigits, mu, ndigits); > + if (mu[ndigits]) > + vli_add(q + ndigits, q + ndigits, product + ndigits, ndigits); > + vli_mult(r, mod, q + ndigits, ndigits); > + vli_sub(r, product, r, ndigits * 2); > + while (!vli_is_zero(r + ndigits, ndigits) || > + vli_cmp(r, mod, ndigits) != -1) { > + u64 carry; > + > + carry = vli_sub(r, r, mod, ndigits); > + vli_usub(r + ndigits, r + ndigits, carry, ndigits); > + } > + vli_set(result, r, ndigits); > +} > + > +/* Computes p_result = p_product % curve_p. > + * See algorithm 5 and 6 from > + * http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf > + */ > +static void vli_mmod_fast_192(u64 *result, const u64 *product, > + const u64 *curve_prime, u64 *tmp) > +{ > + const unsigned int ndigits = ECC_CURVE_NIST_P192_DIGITS; > + int carry; > + > + vli_set(result, product, ndigits); > + > + vli_set(tmp, &product[3], ndigits); > + carry = vli_add(result, result, tmp, ndigits); > + > + tmp[0] = 0; > + tmp[1] = product[3]; > + tmp[2] = product[4]; > + carry += vli_add(result, result, tmp, ndigits); > + > + tmp[0] = tmp[1] = product[5]; > + tmp[2] = 0; > + carry += vli_add(result, result, tmp, ndigits); > + > + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) > + carry -= vli_sub(result, result, curve_prime, ndigits); > +} > + > +/* Computes result = product % curve_prime > + * from http://www.nsa.gov/ia/_files/nist-routines.pdf > + */ > +static void vli_mmod_fast_256(u64 *result, const u64 *product, > + const u64 *curve_prime, u64 *tmp) > +{ > + int carry; > + const unsigned int ndigits = ECC_CURVE_NIST_P256_DIGITS; > + > + /* t */ > + vli_set(result, product, ndigits); > + > + /* s1 */ > + tmp[0] = 0; > + tmp[1] = product[5] & 0xffffffff00000000ull; > + tmp[2] = product[6]; > + tmp[3] = product[7]; > + carry = vli_lshift(tmp, tmp, 1, ndigits); > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s2 */ > + tmp[1] = product[6] << 32; > + tmp[2] = (product[6] >> 32) | (product[7] << 32); > + tmp[3] = product[7] >> 32; > + carry += vli_lshift(tmp, tmp, 1, ndigits); > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s3 */ > + tmp[0] = product[4]; > + tmp[1] = product[5] & 0xffffffff; > + tmp[2] = 0; > + tmp[3] = product[7]; > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s4 */ > + tmp[0] = (product[4] >> 32) | (product[5] << 32); > + tmp[1] = (product[5] >> 32) | (product[6] & 0xffffffff00000000ull); > + tmp[2] = product[7]; > + tmp[3] = (product[6] >> 32) | (product[4] << 32); > + carry += vli_add(result, result, tmp, ndigits); > + > + /* d1 */ > + tmp[0] = (product[5] >> 32) | (product[6] << 32); > + tmp[1] = (product[6] >> 32); > + tmp[2] = 0; > + tmp[3] = (product[4] & 0xffffffff) | (product[5] << 32); > + carry -= vli_sub(result, result, tmp, ndigits); > + > + /* d2 */ > + tmp[0] = product[6]; > + tmp[1] = product[7]; > + tmp[2] = 0; > + tmp[3] = (product[4] >> 32) | (product[5] & 0xffffffff00000000ull); > + carry -= vli_sub(result, result, tmp, ndigits); > + > + /* d3 */ > + tmp[0] = (product[6] >> 32) | (product[7] << 32); > + tmp[1] = (product[7] >> 32) | (product[4] << 32); > + tmp[2] = (product[4] >> 32) | (product[5] << 32); > + tmp[3] = (product[6] << 32); > + carry -= vli_sub(result, result, tmp, ndigits); > + > + /* d4 */ > + tmp[0] = product[7]; > + tmp[1] = product[4] & 0xffffffff00000000ull; > + tmp[2] = product[5]; > + tmp[3] = product[6] & 0xffffffff00000000ull; > + carry -= vli_sub(result, result, tmp, ndigits); > + > + if (carry < 0) { > + do { > + carry += vli_add(result, result, curve_prime, ndigits); > + } while (carry < 0); > + } else { > + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) > + carry -= vli_sub(result, result, curve_prime, ndigits); > + } > +} > + > +#define SL32OR32(x32, y32) (((u64)x32 << 32) | y32) > +#define AND64H(x64) (x64 & 0xffFFffFF00000000ull) > +#define AND64L(x64) (x64 & 0x00000000ffFFffFFull) > + > +/* Computes result = product % curve_prime > + * from "Mathematical routines for the NIST prime elliptic curves" > + */ > +static void vli_mmod_fast_384(u64 *result, const u64 *product, > + const u64 *curve_prime, u64 *tmp) > +{ > + int carry; > + const unsigned int ndigits = ECC_CURVE_NIST_P384_DIGITS; > + > + /* t */ > + vli_set(result, product, ndigits); > + > + /* s1 */ > + tmp[0] = 0; // 0 || 0 > + tmp[1] = 0; // 0 || 0 > + tmp[2] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 > + tmp[3] = product[11]>>32; // 0 ||a23 > + tmp[4] = 0; // 0 || 0 > + tmp[5] = 0; // 0 || 0 > + carry = vli_lshift(tmp, tmp, 1, ndigits); > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s2 */ > + tmp[0] = product[6]; //a13||a12 > + tmp[1] = product[7]; //a15||a14 > + tmp[2] = product[8]; //a17||a16 > + tmp[3] = product[9]; //a19||a18 > + tmp[4] = product[10]; //a21||a20 > + tmp[5] = product[11]; //a23||a22 > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s3 */ > + tmp[0] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 > + tmp[1] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 > + tmp[2] = SL32OR32(product[7], (product[6])>>32); //a14||a13 > + tmp[3] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 > + tmp[4] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 > + tmp[5] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s4 */ > + tmp[0] = AND64H(product[11]); //a23|| 0 > + tmp[1] = (product[10]<<32); //a20|| 0 > + tmp[2] = product[6]; //a13||a12 > + tmp[3] = product[7]; //a15||a14 > + tmp[4] = product[8]; //a17||a16 > + tmp[5] = product[9]; //a19||a18 > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s5 */ > + tmp[0] = 0; // 0|| 0 > + tmp[1] = 0; // 0|| 0 > + tmp[2] = product[10]; //a21||a20 > + tmp[3] = product[11]; //a23||a22 > + tmp[4] = 0; // 0|| 0 > + tmp[5] = 0; // 0|| 0 > + carry += vli_add(result, result, tmp, ndigits); > + > + /* s6 */ > + tmp[0] = AND64L(product[10]); // 0 ||a20 > + tmp[1] = AND64H(product[10]); //a21|| 0 > + tmp[2] = product[11]; //a23||a22 > + tmp[3] = 0; // 0 || 0 > + tmp[4] = 0; // 0 || 0 > + tmp[5] = 0; // 0 || 0 > + carry += vli_add(result, result, tmp, ndigits); > + > + /* d1 */ > + tmp[0] = SL32OR32(product[6], (product[11]>>32)); //a12||a23 > + tmp[1] = SL32OR32(product[7], (product[6]>>32)); //a14||a13 > + tmp[2] = SL32OR32(product[8], (product[7]>>32)); //a16||a15 > + tmp[3] = SL32OR32(product[9], (product[8]>>32)); //a18||a17 > + tmp[4] = SL32OR32(product[10], (product[9]>>32)); //a20||a19 > + tmp[5] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 > + carry -= vli_sub(result, result, tmp, ndigits); > + > + /* d2 */ > + tmp[0] = (product[10]<<32); //a20|| 0 > + tmp[1] = SL32OR32(product[11], (product[10]>>32)); //a22||a21 > + tmp[2] = (product[11]>>32); // 0 ||a23 > + tmp[3] = 0; // 0 || 0 > + tmp[4] = 0; // 0 || 0 > + tmp[5] = 0; // 0 || 0 > + carry -= vli_sub(result, result, tmp, ndigits); > + > + /* d3 */ > + tmp[0] = 0; // 0 || 0 > + tmp[1] = AND64H(product[11]); //a23|| 0 > + tmp[2] = product[11]>>32; // 0 ||a23 > + tmp[3] = 0; // 0 || 0 > + tmp[4] = 0; // 0 || 0 > + tmp[5] = 0; // 0 || 0 > + carry -= vli_sub(result, result, tmp, ndigits); > + > + if (carry < 0) { > + do { > + carry += vli_add(result, result, curve_prime, ndigits); > + } while (carry < 0); > + } else { > + while (carry || vli_cmp(curve_prime, result, ndigits) != 1) > + carry -= vli_sub(result, result, curve_prime, ndigits); > + } > + > +} > + > +#undef SL32OR32 > +#undef AND64H > +#undef AND64L > + > +/* > + * Computes result = product % curve_prime > + * from "Recommendations for Discrete Logarithm-Based Cryptography: > + * Elliptic Curve Domain Parameters" section G.1.4 > + */ > +static void vli_mmod_fast_521(u64 *result, const u64 *product, > + const u64 *curve_prime, u64 *tmp) > +{ > + const unsigned int ndigits = ECC_CURVE_NIST_P521_DIGITS; > + size_t i; > + > + /* Initialize result with lowest 521 bits from product */ > + vli_set(result, product, ndigits); > + result[8] &= 0x1ff; > + > + for (i = 0; i < ndigits; i++) > + tmp[i] = (product[8 + i] >> 9) | (product[9 + i] << 55); > + tmp[8] &= 0x1ff; > + > + vli_mod_add(result, result, tmp, curve_prime, ndigits); > +} > + > +/* Computes result = product % curve_prime for different curve_primes. > + * > + * Note that curve_primes are distinguished just by heuristic check and > + * not by complete conformance check. > + */ > +static bool vli_mmod_fast(u64 *result, u64 *product, > + const struct ecc_curve *curve) > +{ > + u64 tmp[2 * ECC_MAX_DIGITS]; > + const u64 *curve_prime = curve->p; > + const unsigned int ndigits = curve->g.ndigits; > + > + /* All NIST curves have name prefix 'nist_' */ > + if (strncmp(curve->name, "nist_", 5) != 0) { > + /* Try to handle Pseudo-Marsenne primes. */ > + if (curve_prime[ndigits - 1] == -1ull) { > + vli_mmod_special(result, product, curve_prime, > + ndigits); > + return true; > + } else if (curve_prime[ndigits - 1] == 1ull << 63 && > + curve_prime[ndigits - 2] == 0) { > + vli_mmod_special2(result, product, curve_prime, > + ndigits); > + return true; > + } > + vli_mmod_barrett(result, product, curve_prime, ndigits); > + return true; > + } > + > + switch (ndigits) { > + case ECC_CURVE_NIST_P192_DIGITS: > + vli_mmod_fast_192(result, product, curve_prime, tmp); > + break; > + case ECC_CURVE_NIST_P256_DIGITS: > + vli_mmod_fast_256(result, product, curve_prime, tmp); > + break; > + case ECC_CURVE_NIST_P384_DIGITS: > + vli_mmod_fast_384(result, product, curve_prime, tmp); > + break; > + case ECC_CURVE_NIST_P521_DIGITS: > + vli_mmod_fast_521(result, product, curve_prime, tmp); > + break; > + default: > + pr_err("ecc: unsupported digits size!\n"); > + return false; > + } > + > + return true; > +} > + > +/* Computes result = (left * right) % mod. > + * Assumes that mod is big enough curve order. > + */ > +void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right, > + const u64 *mod, unsigned int ndigits) > +{ > + u64 product[ECC_MAX_DIGITS * 2]; > + > + vli_mult(product, left, right, ndigits); > + vli_mmod_slow(result, product, mod, ndigits); > +} > +EXPORT_SYMBOL(vli_mod_mult_slow); > + > +/* Computes result = (left * right) % curve_prime. */ > +static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right, > + const struct ecc_curve *curve) > +{ > + u64 product[2 * ECC_MAX_DIGITS]; > + > + vli_mult(product, left, right, curve->g.ndigits); > + vli_mmod_fast(result, product, curve); > +} > + > +/* Computes result = left^2 % curve_prime. */ > +static void vli_mod_square_fast(u64 *result, const u64 *left, > + const struct ecc_curve *curve) > +{ > + u64 product[2 * ECC_MAX_DIGITS]; > + > + vli_square(product, left, curve->g.ndigits); > + vli_mmod_fast(result, product, curve); > +} > + > +#define EVEN(vli) (!(vli[0] & 1)) > +/* Computes result = (1 / p_input) % mod. All VLIs are the same size. > + * See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" > + * https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf > + */ > +void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod, > + unsigned int ndigits) > +{ > + u64 a[ECC_MAX_DIGITS], b[ECC_MAX_DIGITS]; > + u64 u[ECC_MAX_DIGITS], v[ECC_MAX_DIGITS]; > + u64 carry; > + int cmp_result; > + > + if (vli_is_zero(input, ndigits)) { > + vli_clear(result, ndigits); > + return; > + } > + > + vli_set(a, input, ndigits); > + vli_set(b, mod, ndigits); > + vli_clear(u, ndigits); > + u[0] = 1; > + vli_clear(v, ndigits); > + > + while ((cmp_result = vli_cmp(a, b, ndigits)) != 0) { > + carry = 0; > + > + if (EVEN(a)) { > + vli_rshift1(a, ndigits); > + > + if (!EVEN(u)) > + carry = vli_add(u, u, mod, ndigits); > + > + vli_rshift1(u, ndigits); > + if (carry) > + u[ndigits - 1] |= 0x8000000000000000ull; > + } else if (EVEN(b)) { > + vli_rshift1(b, ndigits); > + > + if (!EVEN(v)) > + carry = vli_add(v, v, mod, ndigits); > + > + vli_rshift1(v, ndigits); > + if (carry) > + v[ndigits - 1] |= 0x8000000000000000ull; > + } else if (cmp_result > 0) { > + vli_sub(a, a, b, ndigits); > + vli_rshift1(a, ndigits); > + > + if (vli_cmp(u, v, ndigits) < 0) > + vli_add(u, u, mod, ndigits); > + > + vli_sub(u, u, v, ndigits); > + if (!EVEN(u)) > + carry = vli_add(u, u, mod, ndigits); > + > + vli_rshift1(u, ndigits); > + if (carry) > + u[ndigits - 1] |= 0x8000000000000000ull; > + } else { > + vli_sub(b, b, a, ndigits); > + vli_rshift1(b, ndigits); > + > + if (vli_cmp(v, u, ndigits) < 0) > + vli_add(v, v, mod, ndigits); > + > + vli_sub(v, v, u, ndigits); > + if (!EVEN(v)) > + carry = vli_add(v, v, mod, ndigits); > + > + vli_rshift1(v, ndigits); > + if (carry) > + v[ndigits - 1] |= 0x8000000000000000ull; > + } > + } > + > + vli_set(result, u, ndigits); > +} > +EXPORT_SYMBOL(vli_mod_inv); > + > +/* ------ Point operations ------ */ > + > +/* Returns true if p_point is the point at infinity, false otherwise. */ > +bool ecc_point_is_zero(const struct ecc_point *point) > +{ > + return (vli_is_zero(point->x, point->ndigits) && > + vli_is_zero(point->y, point->ndigits)); > +} > +EXPORT_SYMBOL(ecc_point_is_zero); > + > +/* Point multiplication algorithm using Montgomery's ladder with co-Z > + * coordinates. From https://eprint.iacr.org/2011/338.pdf > + */ > + > +/* Double in place */ > +static void ecc_point_double_jacobian(u64 *x1, u64 *y1, u64 *z1, > + const struct ecc_curve *curve) > +{ > + /* t1 = x, t2 = y, t3 = z */ > + u64 t4[ECC_MAX_DIGITS]; > + u64 t5[ECC_MAX_DIGITS]; > + const u64 *curve_prime = curve->p; > + const unsigned int ndigits = curve->g.ndigits; > + > + if (vli_is_zero(z1, ndigits)) > + return; > + > + /* t4 = y1^2 */ > + vli_mod_square_fast(t4, y1, curve); > + /* t5 = x1*y1^2 = A */ > + vli_mod_mult_fast(t5, x1, t4, curve); > + /* t4 = y1^4 */ > + vli_mod_square_fast(t4, t4, curve); > + /* t2 = y1*z1 = z3 */ > + vli_mod_mult_fast(y1, y1, z1, curve); > + /* t3 = z1^2 */ > + vli_mod_square_fast(z1, z1, curve); > + > + /* t1 = x1 + z1^2 */ > + vli_mod_add(x1, x1, z1, curve_prime, ndigits); > + /* t3 = 2*z1^2 */ > + vli_mod_add(z1, z1, z1, curve_prime, ndigits); > + /* t3 = x1 - z1^2 */ > + vli_mod_sub(z1, x1, z1, curve_prime, ndigits); > + /* t1 = x1^2 - z1^4 */ > + vli_mod_mult_fast(x1, x1, z1, curve); > + > + /* t3 = 2*(x1^2 - z1^4) */ > + vli_mod_add(z1, x1, x1, curve_prime, ndigits); > + /* t1 = 3*(x1^2 - z1^4) */ > + vli_mod_add(x1, x1, z1, curve_prime, ndigits); > + if (vli_test_bit(x1, 0)) { > + u64 carry = vli_add(x1, x1, curve_prime, ndigits); > + > + vli_rshift1(x1, ndigits); > + x1[ndigits - 1] |= carry << 63; > + } else { > + vli_rshift1(x1, ndigits); > + } > + /* t1 = 3/2*(x1^2 - z1^4) = B */ > + > + /* t3 = B^2 */ > + vli_mod_square_fast(z1, x1, curve); > + /* t3 = B^2 - A */ > + vli_mod_sub(z1, z1, t5, curve_prime, ndigits); > + /* t3 = B^2 - 2A = x3 */ > + vli_mod_sub(z1, z1, t5, curve_prime, ndigits); > + /* t5 = A - x3 */ > + vli_mod_sub(t5, t5, z1, curve_prime, ndigits); > + /* t1 = B * (A - x3) */ > + vli_mod_mult_fast(x1, x1, t5, curve); > + /* t4 = B * (A - x3) - y1^4 = y3 */ > + vli_mod_sub(t4, x1, t4, curve_prime, ndigits); > + > + vli_set(x1, z1, ndigits); > + vli_set(z1, y1, ndigits); > + vli_set(y1, t4, ndigits); > +} > + > +/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ > +static void apply_z(u64 *x1, u64 *y1, u64 *z, const struct ecc_curve *curve) > +{ > + u64 t1[ECC_MAX_DIGITS]; > + > + vli_mod_square_fast(t1, z, curve); /* z^2 */ > + vli_mod_mult_fast(x1, x1, t1, curve); /* x1 * z^2 */ > + vli_mod_mult_fast(t1, t1, z, curve); /* z^3 */ > + vli_mod_mult_fast(y1, y1, t1, curve); /* y1 * z^3 */ > +} > + > +/* P = (x1, y1) => 2P, (x2, y2) => P' */ > +static void xycz_initial_double(u64 *x1, u64 *y1, u64 *x2, u64 *y2, > + u64 *p_initial_z, const struct ecc_curve *curve) > +{ > + u64 z[ECC_MAX_DIGITS]; > + const unsigned int ndigits = curve->g.ndigits; > + > + vli_set(x2, x1, ndigits); > + vli_set(y2, y1, ndigits); > + > + vli_clear(z, ndigits); > + z[0] = 1; > + > + if (p_initial_z) > + vli_set(z, p_initial_z, ndigits); > + > + apply_z(x1, y1, z, curve); > + > + ecc_point_double_jacobian(x1, y1, z, curve); > + > + apply_z(x2, y2, z, curve); > +} > + > +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) > + * Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) > + * or P => P', Q => P + Q > + */ > +static void xycz_add(u64 *x1, u64 *y1, u64 *x2, u64 *y2, > + const struct ecc_curve *curve) > +{ > + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ > + u64 t5[ECC_MAX_DIGITS]; > + const u64 *curve_prime = curve->p; > + const unsigned int ndigits = curve->g.ndigits; > + > + /* t5 = x2 - x1 */ > + vli_mod_sub(t5, x2, x1, curve_prime, ndigits); > + /* t5 = (x2 - x1)^2 = A */ > + vli_mod_square_fast(t5, t5, curve); > + /* t1 = x1*A = B */ > + vli_mod_mult_fast(x1, x1, t5, curve); > + /* t3 = x2*A = C */ > + vli_mod_mult_fast(x2, x2, t5, curve); > + /* t4 = y2 - y1 */ > + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); > + /* t5 = (y2 - y1)^2 = D */ > + vli_mod_square_fast(t5, y2, curve); > + > + /* t5 = D - B */ > + vli_mod_sub(t5, t5, x1, curve_prime, ndigits); > + /* t5 = D - B - C = x3 */ > + vli_mod_sub(t5, t5, x2, curve_prime, ndigits); > + /* t3 = C - B */ > + vli_mod_sub(x2, x2, x1, curve_prime, ndigits); > + /* t2 = y1*(C - B) */ > + vli_mod_mult_fast(y1, y1, x2, curve); > + /* t3 = B - x3 */ > + vli_mod_sub(x2, x1, t5, curve_prime, ndigits); > + /* t4 = (y2 - y1)*(B - x3) */ > + vli_mod_mult_fast(y2, y2, x2, curve); > + /* t4 = y3 */ > + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); > + > + vli_set(x2, t5, ndigits); > +} > + > +/* Input P = (x1, y1, Z), Q = (x2, y2, Z) > + * Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) > + * or P => P - Q, Q => P + Q > + */ > +static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2, > + const struct ecc_curve *curve) > +{ > + /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ > + u64 t5[ECC_MAX_DIGITS]; > + u64 t6[ECC_MAX_DIGITS]; > + u64 t7[ECC_MAX_DIGITS]; > + const u64 *curve_prime = curve->p; > + const unsigned int ndigits = curve->g.ndigits; > + > + /* t5 = x2 - x1 */ > + vli_mod_sub(t5, x2, x1, curve_prime, ndigits); > + /* t5 = (x2 - x1)^2 = A */ > + vli_mod_square_fast(t5, t5, curve); > + /* t1 = x1*A = B */ > + vli_mod_mult_fast(x1, x1, t5, curve); > + /* t3 = x2*A = C */ > + vli_mod_mult_fast(x2, x2, t5, curve); > + /* t4 = y2 + y1 */ > + vli_mod_add(t5, y2, y1, curve_prime, ndigits); > + /* t4 = y2 - y1 */ > + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); > + > + /* t6 = C - B */ > + vli_mod_sub(t6, x2, x1, curve_prime, ndigits); > + /* t2 = y1 * (C - B) */ > + vli_mod_mult_fast(y1, y1, t6, curve); > + /* t6 = B + C */ > + vli_mod_add(t6, x1, x2, curve_prime, ndigits); > + /* t3 = (y2 - y1)^2 */ > + vli_mod_square_fast(x2, y2, curve); > + /* t3 = x3 */ > + vli_mod_sub(x2, x2, t6, curve_prime, ndigits); > + > + /* t7 = B - x3 */ > + vli_mod_sub(t7, x1, x2, curve_prime, ndigits); > + /* t4 = (y2 - y1)*(B - x3) */ > + vli_mod_mult_fast(y2, y2, t7, curve); > + /* t4 = y3 */ > + vli_mod_sub(y2, y2, y1, curve_prime, ndigits); > + > + /* t7 = (y2 + y1)^2 = F */ > + vli_mod_square_fast(t7, t5, curve); > + /* t7 = x3' */ > + vli_mod_sub(t7, t7, t6, curve_prime, ndigits); > + /* t6 = x3' - B */ > + vli_mod_sub(t6, t7, x1, curve_prime, ndigits); > + /* t6 = (y2 + y1)*(x3' - B) */ > + vli_mod_mult_fast(t6, t6, t5, curve); > + /* t2 = y3' */ > + vli_mod_sub(y1, t6, y1, curve_prime, ndigits); > + > + vli_set(x1, t7, ndigits); > +} > + > +static void ecc_point_mult(struct ecc_point *result, > + const struct ecc_point *point, const u64 *scalar, > + u64 *initial_z, const struct ecc_curve *curve, > + unsigned int ndigits) > +{ > + /* R0 and R1 */ > + u64 rx[2][ECC_MAX_DIGITS]; > + u64 ry[2][ECC_MAX_DIGITS]; > + u64 z[ECC_MAX_DIGITS]; > + u64 sk[2][ECC_MAX_DIGITS]; > + u64 *curve_prime = curve->p; > + int i, nb; > + int num_bits; > + int carry; > + > + carry = vli_add(sk[0], scalar, curve->n, ndigits); > + vli_add(sk[1], sk[0], curve->n, ndigits); > + scalar = sk[!carry]; > + if (curve->nbits == 521) /* NIST P521 */ > + num_bits = curve->nbits + 2; > + else > + num_bits = sizeof(u64) * ndigits * 8 + 1; > + > + vli_set(rx[1], point->x, ndigits); > + vli_set(ry[1], point->y, ndigits); > + > + xycz_initial_double(rx[1], ry[1], rx[0], ry[0], initial_z, curve); > + > + for (i = num_bits - 2; i > 0; i--) { > + nb = !vli_test_bit(scalar, i); > + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); > + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); > + } > + > + nb = !vli_test_bit(scalar, 0); > + xycz_add_c(rx[1 - nb], ry[1 - nb], rx[nb], ry[nb], curve); > + > + /* Find final 1/Z value. */ > + /* X1 - X0 */ > + vli_mod_sub(z, rx[1], rx[0], curve_prime, ndigits); > + /* Yb * (X1 - X0) */ > + vli_mod_mult_fast(z, z, ry[1 - nb], curve); > + /* xP * Yb * (X1 - X0) */ > + vli_mod_mult_fast(z, z, point->x, curve); > + > + /* 1 / (xP * Yb * (X1 - X0)) */ > + vli_mod_inv(z, z, curve_prime, point->ndigits); > + > + /* yP / (xP * Yb * (X1 - X0)) */ > + vli_mod_mult_fast(z, z, point->y, curve); > + /* Xb * yP / (xP * Yb * (X1 - X0)) */ > + vli_mod_mult_fast(z, z, rx[1 - nb], curve); > + /* End 1/Z calculation */ > + > + xycz_add(rx[nb], ry[nb], rx[1 - nb], ry[1 - nb], curve); > + > + apply_z(rx[0], ry[0], z, curve); > + > + vli_set(result->x, rx[0], ndigits); > + vli_set(result->y, ry[0], ndigits); > +} > + > +/* Computes R = P + Q mod p */ > +static void ecc_point_add(const struct ecc_point *result, > + const struct ecc_point *p, const struct ecc_point *q, > + const struct ecc_curve *curve) > +{ > + u64 z[ECC_MAX_DIGITS]; > + u64 px[ECC_MAX_DIGITS]; > + u64 py[ECC_MAX_DIGITS]; > + unsigned int ndigits = curve->g.ndigits; > + > + vli_set(result->x, q->x, ndigits); > + vli_set(result->y, q->y, ndigits); > + vli_mod_sub(z, result->x, p->x, curve->p, ndigits); > + vli_set(px, p->x, ndigits); > + vli_set(py, p->y, ndigits); > + xycz_add(px, py, result->x, result->y, curve); > + vli_mod_inv(z, z, curve->p, ndigits); > + apply_z(result->x, result->y, z, curve); > +} > + > +/* Computes R = u1P + u2Q mod p using Shamir's trick. > + * Based on: Kenneth MacKay's micro-ecc (2014). > + */ > +void ecc_point_mult_shamir(const struct ecc_point *result, > + const u64 *u1, const struct ecc_point *p, > + const u64 *u2, const struct ecc_point *q, > + const struct ecc_curve *curve) > +{ > + u64 z[ECC_MAX_DIGITS]; > + u64 sump[2][ECC_MAX_DIGITS]; > + u64 *rx = result->x; > + u64 *ry = result->y; > + unsigned int ndigits = curve->g.ndigits; > + unsigned int num_bits; > + struct ecc_point sum = ECC_POINT_INIT(sump[0], sump[1], ndigits); > + const struct ecc_point *points[4]; > + const struct ecc_point *point; > + unsigned int idx; > + int i; > + > + ecc_point_add(&sum, p, q, curve); > + points[0] = NULL; > + points[1] = p; > + points[2] = q; > + points[3] = ∑ > + > + num_bits = max(vli_num_bits(u1, ndigits), vli_num_bits(u2, ndigits)); > + i = num_bits - 1; > + idx = !!vli_test_bit(u1, i); > + idx |= (!!vli_test_bit(u2, i)) << 1; > + point = points[idx]; > + > + vli_set(rx, point->x, ndigits); > + vli_set(ry, point->y, ndigits); > + vli_clear(z + 1, ndigits - 1); > + z[0] = 1; > + > + for (--i; i >= 0; i--) { > + ecc_point_double_jacobian(rx, ry, z, curve); > + idx = !!vli_test_bit(u1, i); > + idx |= (!!vli_test_bit(u2, i)) << 1; > + point = points[idx]; > + if (point) { > + u64 tx[ECC_MAX_DIGITS]; > + u64 ty[ECC_MAX_DIGITS]; > + u64 tz[ECC_MAX_DIGITS]; > + > + vli_set(tx, point->x, ndigits); > + vli_set(ty, point->y, ndigits); > + apply_z(tx, ty, z, curve); > + vli_mod_sub(tz, rx, tx, curve->p, ndigits); > + xycz_add(tx, ty, rx, ry, curve); > + vli_mod_mult_fast(z, z, tz, curve); > + } > + } > + vli_mod_inv(z, z, curve->p, ndigits); > + apply_z(rx, ry, z, curve); > +} > +EXPORT_SYMBOL(ecc_point_mult_shamir); > + > +/* > + * This function performs checks equivalent to Appendix A.4.2 of FIPS 186-5. > + * Whereas A.4.2 results in an integer in the interval [1, n-1], this function > + * ensures that the integer is in the range of [2, n-3]. We are slightly > + * stricter because of the currently used scalar multiplication algorithm. > + */ > +static int __ecc_is_key_valid(const struct ecc_curve *curve, > + const u64 *private_key, unsigned int ndigits) > +{ > + u64 one[ECC_MAX_DIGITS] = { 1, }; > + u64 res[ECC_MAX_DIGITS]; > + > + if (!private_key) > + return -EINVAL; > + > + if (curve->g.ndigits != ndigits) > + return -EINVAL; > + > + /* Make sure the private key is in the range [2, n-3]. */ > + if (vli_cmp(one, private_key, ndigits) != -1) > + return -EINVAL; > + vli_sub(res, curve->n, one, ndigits); > + vli_sub(res, res, one, ndigits); > + if (vli_cmp(res, private_key, ndigits) != 1) > + return -EINVAL; > + > + return 0; > +} > + > +int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits, > + const u64 *private_key, unsigned int private_key_len) > +{ > + int nbytes; > + const struct ecc_curve *curve = ecc_get_curve(curve_id); > + > + nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT; > + > + if (private_key_len != nbytes) > + return -EINVAL; > + > + return __ecc_is_key_valid(curve, private_key, ndigits); > +} > +EXPORT_SYMBOL(ecc_is_key_valid); > + > +int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits, > + const u64 *private_key, u64 *public_key) > +{ > + int ret = 0; > + struct ecc_point *pk; > + const struct ecc_curve *curve = ecc_get_curve(curve_id); > + > + if (!private_key) { > + ret = -EINVAL; > + goto out; > + } > + > + pk = ecc_alloc_point(ndigits); > + if (!pk) { > + ret = -ENOMEM; > + goto out; > + } > + > + ecc_point_mult(pk, &curve->g, private_key, NULL, curve, ndigits); > + > + /* 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; > + } > + > + ecc_swap_digits(pk->x, public_key, ndigits); > + ecc_swap_digits(pk->y, &public_key[ndigits], ndigits); > + > +err_free_point: > + ecc_free_point(pk); > +out: > + return ret; > +} > +EXPORT_SYMBOL(ecc_make_pub_key); > + > +/* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */ > +int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, > + struct ecc_point *pk) > +{ > + u64 yy[ECC_MAX_DIGITS], xxx[ECC_MAX_DIGITS], w[ECC_MAX_DIGITS]; > + > + if (WARN_ON(pk->ndigits != curve->g.ndigits)) > + return -EINVAL; > + > + /* Check 1: Verify key is not the zero point. */ > + if (ecc_point_is_zero(pk)) > + return -EINVAL; > + > + /* Check 2: Verify key is in the range [1, p-1]. */ > + if (vli_cmp(curve->p, pk->x, pk->ndigits) != 1) > + return -EINVAL; > + if (vli_cmp(curve->p, pk->y, pk->ndigits) != 1) > + return -EINVAL; > + > + /* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */ > + vli_mod_square_fast(yy, pk->y, curve); /* y^2 */ > + vli_mod_square_fast(xxx, pk->x, curve); /* x^2 */ > + vli_mod_mult_fast(xxx, xxx, pk->x, curve); /* x^3 */ > + vli_mod_mult_fast(w, curve->a, pk->x, curve); /* a·x */ > + vli_mod_add(w, w, curve->b, curve->p, pk->ndigits); /* a·x + b */ > + vli_mod_add(w, w, xxx, curve->p, pk->ndigits); /* x^3 + a·x + b */ > + if (vli_cmp(yy, w, pk->ndigits) != 0) /* Equation */ > + return -EINVAL; > + > + return 0; > +} > +EXPORT_SYMBOL(ecc_is_pubkey_valid_partial); > + > +/* SP800-56A section 5.6.2.3.3 full verification */ > +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) > +{ > + int ret = 0; > + struct ecc_point *product, *pk; > + u64 rand_z[ECC_MAX_DIGITS]; > + unsigned int nbytes; > + const struct ecc_curve *curve = ecc_get_curve(curve_id); > + > + if (!private_key || !public_key || ndigits > ARRAY_SIZE(rand_z)) { > + ret = -EINVAL; > + goto out; > + } > + > + nbytes = ndigits << ECC_DIGITS_TO_BYTES_SHIFT; > + > + get_random_bytes(rand_z, nbytes); > + > + pk = ecc_alloc_point(ndigits); > + if (!pk) { > + ret = -ENOMEM; > + goto out; > + } > + > + ecc_swap_digits(public_key, pk->x, ndigits); > + ecc_swap_digits(&public_key[ndigits], pk->y, ndigits); > + ret = ecc_is_pubkey_valid_partial(curve, pk); > + if (ret) > + goto err_alloc_product; > + > + product = ecc_alloc_point(ndigits); > + if (!product) { > + ret = -ENOMEM; > + goto err_alloc_product; > + } > + > + ecc_point_mult(product, pk, private_key, rand_z, curve, ndigits); > + > + if (ecc_point_is_zero(product)) { > + ret = -EFAULT; > + goto err_validity; > + } > + > + ecc_swap_digits(product->x, secret, ndigits); > + > +err_validity: > + memzero_explicit(rand_z, sizeof(rand_z)); > + ecc_free_point(product); > +err_alloc_product: > + ecc_free_point(pk); > +out: > + return ret; > +} > +EXPORT_SYMBOL(crypto_ecdh_shared_secret); > + > +MODULE_LICENSE("Dual BSD/GPL"); > diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h > new file mode 100644 > index 0000000000..0ecade7d02 > --- /dev/null > +++ b/crypto/ecc_curve_defs.h > @@ -0,0 +1,155 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef _CRYTO_ECC_CURVE_DEFS_H > +#define _CRYTO_ECC_CURVE_DEFS_H > + > +/* NIST P-192: a = p - 3 */ > +static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, > + 0x188DA80EB03090F6ull }; > +static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, > + 0x07192B95FFC8DA78ull }; > +static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull, > + 0xFFFFFFFFFFFFFFFFull }; > +static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull, > + 0xFFFFFFFFFFFFFFFFull }; > +static u64 nist_p192_a[] = { 0xFFFFFFFFFFFFFFFCull, 0xFFFFFFFFFFFFFFFEull, > + 0xFFFFFFFFFFFFFFFFull }; > +static u64 nist_p192_b[] = { 0xFEB8DEECC146B9B1ull, 0x0FA7E9AB72243049ull, > + 0x64210519E59C80E7ull }; > +static struct ecc_curve nist_p192 = { > + .name = "nist_192", > + .nbits = 192, > + .g = { > + .x = nist_p192_g_x, > + .y = nist_p192_g_y, > + .ndigits = 3, > + }, > + .p = nist_p192_p, > + .n = nist_p192_n, > + .a = nist_p192_a, > + .b = nist_p192_b > +}; > + > +/* NIST P-256: a = p - 3 */ > +static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, > + 0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull }; > +static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, > + 0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull }; > +static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, > + 0x0000000000000000ull, 0xFFFFFFFF00000001ull }; > +static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, > + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }; > +static u64 nist_p256_a[] = { 0xFFFFFFFFFFFFFFFCull, 0x00000000FFFFFFFFull, > + 0x0000000000000000ull, 0xFFFFFFFF00000001ull }; > +static u64 nist_p256_b[] = { 0x3BCE3C3E27D2604Bull, 0x651D06B0CC53B0F6ull, > + 0xB3EBBD55769886BCull, 0x5AC635D8AA3A93E7ull }; > +static struct ecc_curve nist_p256 = { > + .name = "nist_256", > + .nbits = 256, > + .g = { > + .x = nist_p256_g_x, > + .y = nist_p256_g_y, > + .ndigits = 4, > + }, > + .p = nist_p256_p, > + .n = nist_p256_n, > + .a = nist_p256_a, > + .b = nist_p256_b > +}; > + > +/* NIST P-384 */ > +static u64 nist_p384_g_x[] = { 0x3A545E3872760AB7ull, 0x5502F25DBF55296Cull, > + 0x59F741E082542A38ull, 0x6E1D3B628BA79B98ull, > + 0x8Eb1C71EF320AD74ull, 0xAA87CA22BE8B0537ull }; > +static u64 nist_p384_g_y[] = { 0x7A431D7C90EA0E5Full, 0x0A60B1CE1D7E819Dull, > + 0xE9DA3113B5F0B8C0ull, 0xF8F41DBD289A147Cull, > + 0x5D9E98BF9292DC29ull, 0x3617DE4A96262C6Full }; > +static u64 nist_p384_p[] = { 0x00000000FFFFFFFFull, 0xFFFFFFFF00000000ull, > + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, > + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; > +static u64 nist_p384_n[] = { 0xECEC196ACCC52973ull, 0x581A0DB248B0A77Aull, > + 0xC7634D81F4372DDFull, 0xFFFFFFFFFFFFFFFFull, > + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; > +static u64 nist_p384_a[] = { 0x00000000FFFFFFFCull, 0xFFFFFFFF00000000ull, > + 0xFFFFFFFFFFFFFFFEull, 0xFFFFFFFFFFFFFFFFull, > + 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull }; > +static u64 nist_p384_b[] = { 0x2a85c8edd3ec2aefull, 0xc656398d8a2ed19dull, > + 0x0314088f5013875aull, 0x181d9c6efe814112ull, > + 0x988e056be3f82d19ull, 0xb3312fa7e23ee7e4ull }; > +static struct ecc_curve nist_p384 = { > + .name = "nist_384", > + .nbits = 384, > + .g = { > + .x = nist_p384_g_x, > + .y = nist_p384_g_y, > + .ndigits = 6, > + }, > + .p = nist_p384_p, > + .n = nist_p384_n, > + .a = nist_p384_a, > + .b = nist_p384_b > +}; > + > +/* NIST P-521 */ > +static u64 nist_p521_g_x[] = { 0xf97e7e31c2e5bd66ull, 0x3348b3c1856a429bull, > + 0xfe1dc127a2ffa8deull, 0xa14b5e77efe75928ull, > + 0xf828af606b4d3dbaull, 0x9c648139053fb521ull, > + 0x9e3ecb662395b442ull, 0x858e06b70404e9cdull, > + 0xc6ull }; > +static u64 nist_p521_g_y[] = { 0x88be94769fd16650ull, 0x353c7086a272c240ull, > + 0xc550b9013fad0761ull, 0x97ee72995ef42640ull, > + 0x17afbd17273e662cull, 0x98f54449579b4468ull, > + 0x5c8a5fb42c7d1bd9ull, 0x39296a789a3bc004ull, > + 0x118ull }; > +static u64 nist_p521_p[] = { 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0x1ffull }; > +static u64 nist_p521_n[] = { 0xbb6fb71e91386409ull, 0x3bb5c9b8899c47aeull, > + 0x7fcc0148f709a5d0ull, 0x51868783bf2f966bull, > + 0xfffffffffffffffaull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0x1ffull }; > +static u64 nist_p521_a[] = { 0xfffffffffffffffcull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0xffffffffffffffffull, 0xffffffffffffffffull, > + 0x1ffull }; > +static u64 nist_p521_b[] = { 0xef451fd46b503f00ull, 0x3573df883d2c34f1ull, > + 0x1652c0bd3bb1bf07ull, 0x56193951ec7e937bull, > + 0xb8b489918ef109e1ull, 0xa2da725b99b315f3ull, > + 0x929a21a0b68540eeull, 0x953eb9618e1c9a1full, > + 0x051ull }; > +static struct ecc_curve nist_p521 = { > + .name = "nist_521", > + .nbits = 521, > + .g = { > + .x = nist_p521_g_x, > + .y = nist_p521_g_y, > + .ndigits = 9, > + }, > + .p = nist_p521_p, > + .n = nist_p521_n, > + .a = nist_p521_a, > + .b = nist_p521_b > +}; > + > +/* curve25519 */ > +static u64 curve25519_g_x[] = { 0x0000000000000009, 0x0000000000000000, > + 0x0000000000000000, 0x0000000000000000 }; > +static u64 curve25519_p[] = { 0xffffffffffffffed, 0xffffffffffffffff, > + 0xffffffffffffffff, 0x7fffffffffffffff }; > +static u64 curve25519_a[] = { 0x000000000001DB41, 0x0000000000000000, > + 0x0000000000000000, 0x0000000000000000 }; > +static const struct ecc_curve ecc_25519 = { > + .name = "curve25519", > + .nbits = 255, > + .g = { > + .x = curve25519_g_x, > + .ndigits = 4, > + }, > + .p = curve25519_p, > + .a = curve25519_a, > +}; > + > +#endif > diff --git a/include/crypto/ecc_curve.h b/include/crypto/ecc_curve.h > new file mode 100644 > index 0000000000..7d90c5e822 > --- /dev/null > +++ b/include/crypto/ecc_curve.h > @@ -0,0 +1,62 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* Copyright (c) 2021 HiSilicon */ > + > +#ifndef _CRYTO_ECC_CURVE_H > +#define _CRYTO_ECC_CURVE_H > + > +#include <linux/types.h> > + > +/** > + * struct ecc_point - elliptic curve point in affine coordinates > + * > + * @x: X coordinate in vli form. > + * @y: Y coordinate in vli form. > + * @ndigits: Length of vlis in u64 qwords. > + */ > +struct ecc_point { > + u64 *x; > + u64 *y; > + u8 ndigits; > +}; > + > +/** > + * struct ecc_curve - definition of elliptic curve > + * > + * @name: Short name of the curve. > + * @nbits: The number of bits of a curve. > + * @g: Generator point of the curve. > + * @p: Prime number, if Barrett's reduction is used for this curve > + * pre-calculated value 'mu' is appended to the @p after ndigits. > + * Use of Barrett's reduction is heuristically determined in > + * vli_mmod_fast(). > + * @n: Order of the curve group. > + * @a: Curve parameter a. > + * @b: Curve parameter b. > + */ > +struct ecc_curve { > + char *name; > + u32 nbits; > + struct ecc_point g; > + u64 *p; > + u64 *n; > + u64 *a; > + u64 *b; > +}; > + > +/** > + * ecc_get_curve() - get elliptic curve; > + * @curve_id: Curves IDs: > + * defined in 'include/crypto/ecdh.h'; > + * > + * Returns curve if get curve succssful, NULL otherwise > + */ > +const struct ecc_curve *ecc_get_curve(unsigned int curve_id); > + > +/** > + * ecc_get_curve25519() - get curve25519 curve; > + * > + * Returns curve25519 > + */ > +const struct ecc_curve *ecc_get_curve25519(void); > + > +#endif > diff --git a/include/crypto/ecdh.h b/include/crypto/ecdh.h > new file mode 100644 > index 0000000000..9784ecdd2f > --- /dev/null > +++ b/include/crypto/ecdh.h > @@ -0,0 +1,83 @@ > +/* SPDX-License-Identifier: GPL-2.0-or-later */ > +/* > + * ECDH params to be used with kpp API > + * > + * Copyright (c) 2016, Intel Corporation > + * Authors: Salvatore Benedetto <salvatore.benedetto@intel.com> > + */ > +#ifndef _CRYPTO_ECDH_ > +#define _CRYPTO_ECDH_ > + > +/** > + * DOC: ECDH Helper Functions > + * > + * To use ECDH with the KPP cipher API, the following data structure and > + * functions should be used. > + * > + * The ECC curves known to the ECDH implementation are specified in this > + * header file. > + * > + * To use ECDH with KPP, the following functions should be used to operate on > + * an ECDH private key. The packet private key that can be set with > + * the KPP API function call of crypto_kpp_set_secret. > + */ > + > +/* Curves IDs */ > +#define ECC_CURVE_NIST_P192 0x0001 > +#define ECC_CURVE_NIST_P256 0x0002 > +#define ECC_CURVE_NIST_P384 0x0003 > +#define ECC_CURVE_NIST_P521 0x0004 > + > +/** > + * struct ecdh - define an ECDH private key > + * > + * @key: Private ECDH key > + * @key_size: Size of the private ECDH key > + */ > +struct ecdh { > + char *key; > + unsigned short key_size; > +}; > + > +/** > + * crypto_ecdh_key_len() - Obtain the size of the private ECDH key > + * @params: private ECDH key > + * > + * This function returns the packet ECDH key size. A caller can use that > + * with the provided ECDH private key reference to obtain the required > + * memory size to hold a packet key. > + * > + * Return: size of the key in bytes > + */ > +unsigned int crypto_ecdh_key_len(const struct ecdh *params); > + > +/** > + * crypto_ecdh_encode_key() - encode the private key > + * @buf: Buffer allocated by the caller to hold the packet ECDH > + * private key. The buffer should be at least crypto_ecdh_key_len > + * bytes in size. > + * @len: Length of the packet private key buffer > + * @p: Buffer with the caller-specified private key > + * > + * The ECDH implementations operate on a packet representation of the private > + * key. > + * > + * Return: -EINVAL if buffer has insufficient size, 0 on success > + */ > +int crypto_ecdh_encode_key(char *buf, unsigned int len, const struct ecdh *p); > + > +/** > + * crypto_ecdh_decode_key() - decode a private key > + * @buf: Buffer holding a packet key that should be decoded > + * @len: Length of the packet private key buffer > + * @p: Buffer allocated by the caller that is filled with the > + * unpacked ECDH private key. > + * > + * The unpacking obtains the private key by pointing @p to the correct location > + * in @buf. Thus, both pointers refer to the same memory. > + * > + * Return: -EINVAL if buffer has insufficient size, 0 on success > + */ > +int crypto_ecdh_decode_key(const char *buf, unsigned int len, struct ecdh *p); > + > +#endif > diff --git a/include/crypto/internal/ecc.h b/include/crypto/internal/ecc.h > new file mode 100644 > index 0000000000..f191491cc0 > --- /dev/null > +++ b/include/crypto/internal/ecc.h > @@ -0,0 +1,278 @@ > +/* > + * Copyright (c) 2013, Kenneth MacKay > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions are > + * met: > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + */ > +#ifndef _CRYPTO_ECC_H > +#define _CRYPTO_ECC_H > + > +#include <crypto/ecc_curve.h> > +#include <asm/unaligned.h> > + > +/* One digit is u64 qword. */ > +#define ECC_CURVE_NIST_P192_DIGITS 3 > +#define ECC_CURVE_NIST_P256_DIGITS 4 > +#define ECC_CURVE_NIST_P384_DIGITS 6 > +#define ECC_CURVE_NIST_P521_DIGITS 9 > +#define ECC_MAX_DIGITS DIV_ROUND_UP(521, 64) /* NIST P521 */ > + > +#define ECC_DIGITS_TO_BYTES_SHIFT 3 > + > +#define ECC_MAX_BYTES (ECC_MAX_DIGITS << ECC_DIGITS_TO_BYTES_SHIFT) > + > +#define ECC_POINT_INIT(x, y, ndigits) (struct ecc_point) { x, y, ndigits } > + > +/** > + * ecc_swap_digits() - Copy ndigits from big endian array to native array > + * @in: Input array > + * @out: Output array > + * @ndigits: Number of digits to copy > + */ > +static inline void ecc_swap_digits(const void *in, u64 *out, unsigned int ndigits) > +{ > + const __be64 *src = (__force __be64 *)in; > + int i; > + > + for (i = 0; i < ndigits; i++) > + out[i] = get_unaligned_be64(&src[ndigits - 1 - i]); > +} > + > +/** > + * ecc_digits_from_bytes() - Create ndigits-sized digits array from byte array > + * @in: Input byte array > + * @nbytes Size of input byte array > + * @out Output digits array > + * @ndigits: Number of digits to create from byte array > + */ > +void ecc_digits_from_bytes(const u8 *in, unsigned int nbytes, > + u64 *out, unsigned int ndigits); > + > +/** > + * ecc_is_key_valid() - Validate a given ECDH private key > + * > + * @curve_id: id representing the curve to use > + * @ndigits: curve's number of digits > + * @private_key: private key to be used for the given curve > + * @private_key_len: private key length > + * > + * Returns 0 if the key is acceptable, a negative value otherwise > + */ > +int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits, > + const u64 *private_key, unsigned int private_key_len); > + > +/** > + * ecc_make_pub_key() - Compute an ECC public key > + * > + * @curve_id: id representing the curve to use > + * @ndigits: curve's number of digits > + * @private_key: pregenerated private key for the given curve > + * @public_key: buffer for storing the generated public key > + * > + * Returns 0 if the public key was generated successfully, a negative value > + * if an error occurred. > + */ > +int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits, > + const u64 *private_key, u64 *public_key); > + > +/** > + * crypto_ecdh_shared_secret() - Compute a shared secret > + * > + * @curve_id: id representing the curve to use > + * @ndigits: curve's number of digits > + * @private_key: private key of part A > + * @public_key: public key of counterpart B > + * @secret: buffer for storing the calculated shared secret > + * > + * Note: It is recommended that you hash the result of crypto_ecdh_shared_secret > + * before using it for symmetric encryption or HMAC. > + * > + * Returns 0 if the shared secret was generated successfully, a negative value > + * if an error occurred. > + */ > +int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, > + const u64 *private_key, const u64 *public_key, > + u64 *secret); > + > +/** > + * ecc_is_pubkey_valid_partial() - Partial public key validation > + * > + * @curve: elliptic curve domain parameters > + * @pk: public key as a point > + * > + * Valdiate public key according to SP800-56A section 5.6.2.3.4 ECC Partial > + * Public-Key Validation Routine. > + * > + * Note: There is no check that the public key is in the correct elliptic curve > + * subgroup. > + * > + * Return: 0 if validation is successful, -EINVAL if validation is failed. > + */ > +int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve, > + struct ecc_point *pk); > + > +/** > + * ecc_is_pubkey_valid_full() - Full public key validation > + * > + * @curve: elliptic curve domain parameters > + * @pk: public key as a point > + * > + * Valdiate public key according to SP800-56A section 5.6.2.3.3 ECC Full > + * Public-Key Validation Routine. > + * > + * Return: 0 if validation is successful, -EINVAL if validation is failed. > + */ > +int ecc_is_pubkey_valid_full(const struct ecc_curve *curve, > + struct ecc_point *pk); > + > +/** > + * vli_is_zero() - Determine is vli is zero > + * > + * @vli: vli to check. > + * @ndigits: length of the @vli > + */ > +bool vli_is_zero(const u64 *vli, unsigned int ndigits); > + > +/** > + * vli_cmp() - compare left and right vlis > + * > + * @left: vli > + * @right: vli > + * @ndigits: length of both vlis > + * > + * Returns sign of @left - @right, i.e. -1 if @left < @right, > + * 0 if @left == @right, 1 if @left > @right. > + */ > +int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits); > + > +/** > + * vli_sub() - Subtracts right from left > + * > + * @result: where to write result > + * @left: vli > + * @right vli > + * @ndigits: length of all vlis > + * > + * Note: can modify in-place. > + * > + * Return: carry bit. > + */ > +u64 vli_sub(u64 *result, const u64 *left, const u64 *right, > + unsigned int ndigits); > + > +/** > + * vli_from_be64() - Load vli from big-endian u64 array > + * > + * @dest: destination vli > + * @src: source array of u64 BE values > + * @ndigits: length of both vli and array > + */ > +void vli_from_be64(u64 *dest, const void *src, unsigned int ndigits); > + > +/** > + * vli_from_le64() - Load vli from little-endian u64 array > + * > + * @dest: destination vli > + * @src: source array of u64 LE values > + * @ndigits: length of both vli and array > + */ > +void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits); > + > +/** > + * vli_mod_inv() - Modular inversion > + * > + * @result: where to write vli number > + * @input: vli value to operate on > + * @mod: modulus > + * @ndigits: length of all vlis > + */ > +void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod, > + unsigned int ndigits); > + > +/** > + * vli_mod_mult_slow() - Modular multiplication > + * > + * @result: where to write result value > + * @left: vli number to multiply with @right > + * @right: vli number to multiply with @left > + * @mod: modulus > + * @ndigits: length of all vlis > + * > + * Note: Assumes that mod is big enough curve order. > + */ > +void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right, > + const u64 *mod, unsigned int ndigits); > + > +/** > + * vli_num_bits() - Counts the number of bits required for vli. > + * > + * @vli: vli to check. > + * @ndigits: Length of the @vli > + * > + * Return: The number of bits required to represent @vli. > + */ > +unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits); > + > +/** > + * ecc_aloc_point() - Allocate ECC point. > + * > + * @ndigits: Length of vlis in u64 qwords. > + * > + * Return: Pointer to the allocated point or NULL if allocation failed. > + */ > +struct ecc_point *ecc_alloc_point(unsigned int ndigits); > + > +/** > + * ecc_free_point() - Free ECC point. > + * > + * @p: The point to free. > + */ > +void ecc_free_point(struct ecc_point *p); > + > +/** > + * ecc_point_is_zero() - Check if point is zero. > + * > + * @p: Point to check for zero. > + * > + * Return: true if point is the point at infinity, false otherwise. > + */ > +bool ecc_point_is_zero(const struct ecc_point *point); > + > +/** > + * ecc_point_mult_shamir() - Add two points multiplied by scalars > + * > + * @result: resulting point > + * @x: scalar to multiply with @p > + * @p: point to multiply with @x > + * @y: scalar to multiply with @q > + * @q: point to multiply with @y > + * @curve: curve > + * > + * Returns result = x * p + x * q over the curve. > + * This works faster than two multiplications and addition. > + */ > +void ecc_point_mult_shamir(const struct ecc_point *result, > + const u64 *x, const struct ecc_point *p, > + const u64 *y, const struct ecc_point *q, > + const struct ecc_curve *curve); > + > +#endif -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 17/19] crypto: add ECDSA support 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (15 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 16/19] Add elliptic curve cryptography (ECC) helper functions Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 11:57 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 18/19] crypto: make RSA a visible option Sascha Hauer ` (2 subsequent siblings) 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List This adds ECDSA signature verification support. The code is based on the Linux code as of Linux-6.10. The Linux code expects the key to be in ASN.1 encoded format. We don't need this in barebox as directly compile the x and y key values into the binary, so this is left out. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- crypto/Kconfig | 20 ++++ crypto/Makefile | 19 ++++ crypto/ecdsa.c | 169 ++++++++++++++++++++++++++++++ include/asm-generic/barebox.lds.h | 7 ++ include/ecdsa.h | 21 ++++ 5 files changed, 236 insertions(+) create mode 100644 crypto/ecdsa.c create mode 100644 include/ecdsa.h diff --git a/crypto/Kconfig b/crypto/Kconfig index e953ef5e15..eeacd9ffb7 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -156,4 +156,24 @@ config JWT config CRYPTO_ECC bool +config CRYPTO_ECDSA + bool "ECDSA support" + select CRYPTO_ECC + +config CRYPTO_ECDSA_BUILTIN_KEYS + bool + default y if CRYPTO_ECDSA_KEY != "" + select KEYTOC + +config CRYPTO_ECDSA_KEY + depends on CRYPTO_ECDSA + string "ECDSA key to compile in" + help + This option should be a filename of a PEM-formatted file containing + X.509 certificates to be included into barebox. If the string starts + with "pkcs11:" it is interpreted as a PKCS#11 URI rather than a file. + + This avoids the mkimage dependency of CONFIG_BOOTM_FITIMAGE_PUBKEY + at the cost of an openssl build-time dependency. + endmenu diff --git a/crypto/Makefile b/crypto/Makefile index 83c05761de..0bbd495378 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -37,3 +37,22 @@ endif $(obj)/rsa-keys.h: $(RSA_DEP) FORCE $(call cmd,public_keys,$(CONFIG_CRYPTO_RSA_KEY_NAME_HINT):$(if $(RSA_DEP),$<,$(CONFIG_CRYPTO_RSA_KEY))) endif + +extra-$(CONFIG_CRYPTO_ECDSA_BUILTIN_KEYS) += ecdsa-keys.h + +ifdef CONFIG_CRYPTO_ECDSA_BUILTIN_KEYS + +$(obj)/ecdsa.o: $(obj)/ecdsa-keys.h + +CONFIG_CRYPTO_ECDSA_KEY := $(CONFIG_CRYPTO_ECDSA_KEY:"%"=%) + +ifneq ($(filter-out pkcs11:% __ENV__%, $(CONFIG_CRYPTO_ECDSA_KEY)),) +ECDSA_DEP := $(CONFIG_CRYPTO_ECDSA_KEY) +endif + +$(obj)/ecdsa-keys.h: $(ECDSA_DEP) FORCE + $(call cmd,public_keys,ecdsa_key:$(if $(ECDSA_DEP),$<,$(CONFIG_CRYPTO_ECDSA_KEY))) + +endif + +obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa.o diff --git a/crypto/ecdsa.c b/crypto/ecdsa.c new file mode 100644 index 0000000000..d6b534be6d --- /dev/null +++ b/crypto/ecdsa.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 IBM Corporation + */ + +#include <common.h> + +#include <crypto/internal/ecc.h> +#include <crypto/ecdh.h> +#include <ecdsa.h> + +struct ecc_ctx { + unsigned int curve_id; + const struct ecc_curve *curve; + + bool pub_key_set; + u64 x[ECC_MAX_DIGITS]; /* pub key x and y coordinates */ + u64 y[ECC_MAX_DIGITS]; + struct ecc_point pub_key; +}; + +static int _ecdsa_verify(struct ecc_ctx *ctx, const u64 *hash, const u64 *r, const u64 *s) +{ + const struct ecc_curve *curve = ctx->curve; + unsigned int ndigits = curve->g.ndigits; + u64 s1[ECC_MAX_DIGITS]; + u64 u1[ECC_MAX_DIGITS]; + u64 u2[ECC_MAX_DIGITS]; + u64 x1[ECC_MAX_DIGITS]; + u64 y1[ECC_MAX_DIGITS]; + struct ecc_point res = ECC_POINT_INIT(x1, y1, ndigits); + + /* 0 < r < n and 0 < s < n */ + if (vli_is_zero(r, ndigits) || vli_cmp(r, curve->n, ndigits) >= 0 || + vli_is_zero(s, ndigits) || vli_cmp(s, curve->n, ndigits) >= 0) + return -EBADMSG; + + /* hash is given */ + pr_debug("hash : %016llx %016llx ... %016llx\n", + hash[ndigits - 1], hash[ndigits - 2], hash[0]); + + /* s1 = (s^-1) mod n */ + vli_mod_inv(s1, s, curve->n, ndigits); + /* u1 = (hash * s1) mod n */ + vli_mod_mult_slow(u1, hash, s1, curve->n, ndigits); + /* u2 = (r * s1) mod n */ + vli_mod_mult_slow(u2, r, s1, curve->n, ndigits); + /* res = u1*G + u2 * pub_key */ + ecc_point_mult_shamir(&res, u1, &curve->g, u2, &ctx->pub_key, curve); + + /* res.x = res.x mod n (if res.x > order) */ + if (unlikely(vli_cmp(res.x, curve->n, ndigits) == 1)) + /* faster alternative for NIST p521, p384, p256 & p192 */ + vli_sub(res.x, res.x, curve->n, ndigits); + + if (!vli_cmp(res.x, r, ndigits)) + return 0; + + return -EKEYREJECTED; +} + +static int ecdsa_key_size(const char *curve_name) +{ + if (!strcmp(curve_name, "prime256v1")) + return 256; + else + return 0; +} + +int ecdsa_verify(const struct ecdsa_public_key *key, const uint8_t *sig, + const uint32_t sig_len, const uint8_t *hash) +{ + struct ecc_ctx _ctx = {}; + struct ecc_ctx *ctx = &_ctx; + unsigned int curve_id = ECC_CURVE_NIST_P256; + int ret; + const void *r, *s; + u64 rh[4], sh[4]; + u64 mhash[ECC_MAX_DIGITS]; + int key_size_bytes = key->size_bits / 8; + + ctx->curve_id = curve_id; + ctx->curve = ecc_get_curve(curve_id); + if (!ctx->curve) + return -EINVAL; + + ctx->pub_key = ECC_POINT_INIT(ctx->x, ctx->y, ctx->curve->g.ndigits); + memcpy(ctx->pub_key.x, key->x, key_size_bytes); + memcpy(ctx->pub_key.y, key->y, key_size_bytes); + + ret = ecc_is_pubkey_valid_full(ctx->curve, &ctx->pub_key); + if (ret) + return ret; + + r = sig; + s = sig + key_size_bytes; + + ecc_swap_digits((u64 *)r, rh, ctx->curve->g.ndigits); + ecc_swap_digits((u64 *)s, sh, ctx->curve->g.ndigits); + + ecc_swap_digits((u64 *)hash, mhash, ctx->curve->g.ndigits); + + return _ecdsa_verify(ctx, (void *)mhash, rh, sh); +} + +static LIST_HEAD(ecdsa_keys); + +static int ecdsa_key_add(struct ecdsa_public_key *key) +{ + list_add_tail(&key->list, &ecdsa_keys); + + return 0; +} + +const struct ecdsa_public_key *ecdsa_key_next(const struct ecdsa_public_key *prev) +{ + prev = list_prepare_entry(prev, &ecdsa_keys, list); + list_for_each_entry_continue(prev, &ecdsa_keys, list) + return prev; + + return NULL; +} + +static struct ecdsa_public_key *ecdsa_key_dup(const struct ecdsa_public_key *key) +{ + struct ecdsa_public_key *new; + int key_size_bits; + + key_size_bits = ecdsa_key_size(key->curve_name); + if (!key_size_bits) + return NULL; + + new = xmemdup(key, sizeof(*key)); + new->x = xmemdup(key->x, key_size_bits / 8); + new->y = xmemdup(key->y, key_size_bits / 8); + new->size_bits = key_size_bits; + + return new; +} + +extern const struct ecdsa_public_key * const __ecdsa_keys_start; +extern const struct ecdsa_public_key * const __ecdsa_keys_end; + +static int ecdsa_init_keys(void) +{ + const struct ecdsa_public_key * const *iter; + struct ecdsa_public_key *key; + int ret; + + for (iter = &__ecdsa_keys_start; iter != &__ecdsa_keys_end; iter++) { + key = ecdsa_key_dup(*iter); + if (!key) { + pr_err("Ignoring key with unknown curve_name %s\n", key->curve_name); + continue; + } + + ret = ecdsa_key_add(key); + if (ret) + pr_err("Cannot add rsa key: %pe\n", ERR_PTR(ret)); + } + + return 0; +} + +device_initcall(ecdsa_init_keys); + +#ifdef CONFIG_CRYPTO_ECDSA_BUILTIN_KEYS +#include "ecdsa-keys.h" +#endif diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h index d3736ebaed..7f3b86f272 100644 --- a/include/asm-generic/barebox.lds.h +++ b/include/asm-generic/barebox.lds.h @@ -112,6 +112,12 @@ KEEP(*(.rsa_keys.rodata.*)); \ __rsa_keys_end = .; \ +#define BAREBOX_ECDSA_KEYS \ + STRUCT_ALIGN(); \ + __ecdsa_keys_start = .; \ + KEEP(*(.ecdsa_keys.rodata.*)); \ + __ecdsa_keys_end = .; \ + #define BAREBOX_DEEP_PROBE \ STRUCT_ALIGN(); \ __barebox_deep_probe_start = .; \ @@ -141,6 +147,7 @@ BAREBOX_CLK_TABLE \ BAREBOX_DTB \ BAREBOX_RSA_KEYS \ + BAREBOX_ECDSA_KEYS \ BAREBOX_PCI_FIXUP \ BAREBOX_DEEP_PROBE diff --git a/include/ecdsa.h b/include/ecdsa.h new file mode 100644 index 0000000000..e3df15a060 --- /dev/null +++ b/include/ecdsa.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +#ifndef _ECDSA_H +#define _ECDSA_H + +struct ecdsa_public_key { + const char *curve_name; /* Name of curve, e.g. "prime256v1" */ + const void *x; /* x coordinate of public key */ + const void *y; /* y coordinate of public key */ + unsigned int size_bits; /* key size in bits, derived from curve name */ + struct list_head list; +}; + +int ecdsa_verify(const struct ecdsa_public_key *key, const uint8_t *sig, + const uint32_t sig_len, const uint8_t *hash); + +const struct ecdsa_public_key *ecdsa_key_next(const struct ecdsa_public_key *prev); + +#define for_each_ecdsa_key(key) \ + for (key = ecdsa_key_next(NULL); key; key = ecdsa_key_next(key)) + +#endif /* _ECDSA_H */ -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 17/19] crypto: add ECDSA support 2024-08-01 5:57 ` [PATCH v2 17/19] crypto: add ECDSA support Sascha Hauer @ 2024-08-05 11:57 ` Ahmad Fatoum 2024-08-05 12:44 ` Sascha Hauer 0 siblings, 1 reply; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 11:57 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > This adds ECDSA signature verification support. The code is based on the > Linux code as of Linux-6.10. The Linux code expects the key to be in > ASN.1 encoded format. We don't need this in barebox as directly compile > the x and y key values into the binary, so this is left out. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > crypto/Kconfig | 20 ++++ > crypto/Makefile | 19 ++++ > crypto/ecdsa.c | 169 ++++++++++++++++++++++++++++++ > include/asm-generic/barebox.lds.h | 7 ++ > include/ecdsa.h | 21 ++++ > 5 files changed, 236 insertions(+) > create mode 100644 crypto/ecdsa.c > create mode 100644 include/ecdsa.h > > diff --git a/crypto/Kconfig b/crypto/Kconfig > index e953ef5e15..eeacd9ffb7 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -156,4 +156,24 @@ config JWT > config CRYPTO_ECC > bool > > +config CRYPTO_ECDSA > + bool "ECDSA support" > + select CRYPTO_ECC > + > +config CRYPTO_ECDSA_BUILTIN_KEYS > + bool > + default y if CRYPTO_ECDSA_KEY != "" > + select KEYTOC > + > +config CRYPTO_ECDSA_KEY > + depends on CRYPTO_ECDSA > + string "ECDSA key to compile in" > + help > + This option should be a filename of a PEM-formatted file containing > + X.509 certificates to be included into barebox. If the string starts > + with "pkcs11:" it is interpreted as a PKCS#11 URI rather than a file. > + > + This avoids the mkimage dependency of CONFIG_BOOTM_FITIMAGE_PUBKEY > + at the cost of an openssl build-time dependency. Why can't this option take multiple space-separated paths? > +static struct ecdsa_public_key *ecdsa_key_dup(const struct ecdsa_public_key *key) > +{ > + struct ecdsa_public_key *new; > + int key_size_bits; > + > + key_size_bits = ecdsa_key_size(key->curve_name); > + if (!key_size_bits) > + return NULL; > + > + new = xmemdup(key, sizeof(*key)); > + new->x = xmemdup(key->x, key_size_bits / 8); > + new->y = xmemdup(key->y, key_size_bits / 8); > + new->size_bits = key_size_bits; I think you'll want to explicitly initialize the linked list member here instead of leaving it dangling. > + > + return new; > +} > + > +extern const struct ecdsa_public_key * const __ecdsa_keys_start; > +extern const struct ecdsa_public_key * const __ecdsa_keys_end; This looks odd. Shouldn't this be array of unknown size []. > + > +static int ecdsa_init_keys(void) > +{ > + const struct ecdsa_public_key * const *iter; and this would be a single level pointer? > + struct ecdsa_public_key *key; > + int ret; > + > + for (iter = &__ecdsa_keys_start; iter != &__ecdsa_keys_end; iter++) { > + key = ecdsa_key_dup(*iter); > + if (!key) { > + pr_err("Ignoring key with unknown curve_name %s\n", key->curve_name); > + continue; > + } > + > + ret = ecdsa_key_add(key); > + if (ret) > + pr_err("Cannot add rsa key: %pe\n", ERR_PTR(ret)); > + } > + > + return 0; > +} ntifier: GPL-2.0-only > +#ifndef _ECDSA_H > +#define _ECDSA_H > + > +struct ecdsa_public_key { > + const char *curve_name; /* Name of curve, e.g. "prime256v1" */ > + const void *x; /* x coordinate of public key */ > + const void *y; /* y coordinate of public key */ Why void and not a specific type? Cheers, Ahmad -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 17/19] crypto: add ECDSA support 2024-08-05 11:57 ` Ahmad Fatoum @ 2024-08-05 12:44 ` Sascha Hauer 2024-08-06 9:13 ` Ahmad Fatoum 0 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-05 12:44 UTC (permalink / raw) To: Ahmad Fatoum; +Cc: Barebox List On Mon, Aug 05, 2024 at 01:57:36PM +0200, Ahmad Fatoum wrote: > On 01.08.24 07:57, Sascha Hauer wrote: > > This adds ECDSA signature verification support. The code is based on the > > Linux code as of Linux-6.10. The Linux code expects the key to be in > > ASN.1 encoded format. We don't need this in barebox as directly compile > > the x and y key values into the binary, so this is left out. > > > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > > --- > > crypto/Kconfig | 20 ++++ > > crypto/Makefile | 19 ++++ > > crypto/ecdsa.c | 169 ++++++++++++++++++++++++++++++ > > include/asm-generic/barebox.lds.h | 7 ++ > > include/ecdsa.h | 21 ++++ > > 5 files changed, 236 insertions(+) > > create mode 100644 crypto/ecdsa.c > > create mode 100644 include/ecdsa.h > > > > diff --git a/crypto/Kconfig b/crypto/Kconfig > > index e953ef5e15..eeacd9ffb7 100644 > > --- a/crypto/Kconfig > > +++ b/crypto/Kconfig > > @@ -156,4 +156,24 @@ config JWT > > config CRYPTO_ECC > > bool > > > > +config CRYPTO_ECDSA > > + bool "ECDSA support" > > + select CRYPTO_ECC > > + > > +config CRYPTO_ECDSA_BUILTIN_KEYS > > + bool > > + default y if CRYPTO_ECDSA_KEY != "" > > + select KEYTOC > > + > > +config CRYPTO_ECDSA_KEY > > + depends on CRYPTO_ECDSA > > + string "ECDSA key to compile in" > > + help > > + This option should be a filename of a PEM-formatted file containing > > + X.509 certificates to be included into barebox. If the string starts > > + with "pkcs11:" it is interpreted as a PKCS#11 URI rather than a file. > > + > > + This avoids the mkimage dependency of CONFIG_BOOTM_FITIMAGE_PUBKEY > > + at the cost of an openssl build-time dependency. > > Why can't this option take multiple space-separated paths? The code added for ECDSA is mostly a copy from the existing RSA code. It's less than ideal. What I'd really like to have is a single list of keys which can include both RSA and ECDSA keys instead of maintaining multiple lists. Likewise for the Kconfig options, it would be better to have a CRYPTO_PUBLIC_KEYS option which holds multiple RSA and/or ECDSA keys. Unfortunately my time budget for this task is over, so I think we'll have to stick with this until the next cleanup round. > > +#define _ECDSA_H > > + > > +struct ecdsa_public_key { > > + const char *curve_name; /* Name of curve, e.g. "prime256v1" */ > > + const void *x; /* x coordinate of public key */ > > + const void *y; /* y coordinate of public key */ > > Why void and not a specific type? No specific reason, it's copied from U-Boot. One reason might be that keytoc prints the values as array of uint32_t whereas the values in barebox are interpreted as array of uint64_t. Using void * avoids casts and covers some interesting endianess problems when the barebox endianess differs from the endianess of the build machine. Sascha -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 17/19] crypto: add ECDSA support 2024-08-05 12:44 ` Sascha Hauer @ 2024-08-06 9:13 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-06 9:13 UTC (permalink / raw) To: Sascha Hauer; +Cc: Barebox List Hi, On 05.08.24 14:44, Sascha Hauer wrote: > On Mon, Aug 05, 2024 at 01:57:36PM +0200, Ahmad Fatoum wrote: >> On 01.08.24 07:57, Sascha Hauer wrote: >>> This adds ECDSA signature verification support. The code is based on the >>> Linux code as of Linux-6.10. The Linux code expects the key to be in >>> ASN.1 encoded format. We don't need this in barebox as directly compile >>> the x and y key values into the binary, so this is left out. >>> >>> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> >>> --- >>> crypto/Kconfig | 20 ++++ >>> crypto/Makefile | 19 ++++ >>> crypto/ecdsa.c | 169 ++++++++++++++++++++++++++++++ >>> include/asm-generic/barebox.lds.h | 7 ++ >>> include/ecdsa.h | 21 ++++ >>> 5 files changed, 236 insertions(+) >>> create mode 100644 crypto/ecdsa.c >>> create mode 100644 include/ecdsa.h >>> >>> diff --git a/crypto/Kconfig b/crypto/Kconfig >>> index e953ef5e15..eeacd9ffb7 100644 >>> --- a/crypto/Kconfig >>> +++ b/crypto/Kconfig >>> @@ -156,4 +156,24 @@ config JWT >>> config CRYPTO_ECC >>> bool >>> >>> +config CRYPTO_ECDSA >>> + bool "ECDSA support" >>> + select CRYPTO_ECC >>> + >>> +config CRYPTO_ECDSA_BUILTIN_KEYS >>> + bool >>> + default y if CRYPTO_ECDSA_KEY != "" >>> + select KEYTOC >>> + >>> +config CRYPTO_ECDSA_KEY >>> + depends on CRYPTO_ECDSA >>> + string "ECDSA key to compile in" >>> + help >>> + This option should be a filename of a PEM-formatted file containing >>> + X.509 certificates to be included into barebox. If the string starts >>> + with "pkcs11:" it is interpreted as a PKCS#11 URI rather than a file. >>> + >>> + This avoids the mkimage dependency of CONFIG_BOOTM_FITIMAGE_PUBKEY >>> + at the cost of an openssl build-time dependency. >> >> Why can't this option take multiple space-separated paths? > > The code added for ECDSA is mostly a copy from the existing RSA code. > > It's less than ideal. What I'd really like to have is a single list of > keys which can include both RSA and ECDSA keys instead of maintaining > multiple lists. Likewise for the Kconfig options, it would be better to > have a CRYPTO_PUBLIC_KEYS option which holds multiple RSA and/or > ECDSA keys. Unfortunately my time budget for this task is over, so I > think we'll have to stick with this until the next cleanup round. Ok, let's leave it to behave like the RSA options then. >>> +#define _ECDSA_H >>> + >>> +struct ecdsa_public_key { >>> + const char *curve_name; /* Name of curve, e.g. "prime256v1" */ >>> + const void *x; /* x coordinate of public key */ >>> + const void *y; /* y coordinate of public key */ >> >> Why void and not a specific type? > > No specific reason, it's copied from U-Boot. One reason might be that > keytoc prints the values as array of uint32_t whereas the values in > barebox are interpreted as array of uint64_t. Using void * avoids casts > and covers some interesting endianess problems when the barebox > endianess differs from the endianess of the build machine. This looks certainly odd. It's probably worth looking into. Cheers, Ahmad > > Sascha > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 18/19] crypto: make RSA a visible option 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (16 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 17/19] crypto: add ECDSA support Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 10:19 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 19/19] fit: Add ecdsa support Sascha Hauer 2024-08-06 6:03 ` [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List With upcoming ECDSA support RSA won't be the only option for FIT image verification anymore. Make CONFIG_CRYPTO_RSA visible so that the user can choose. CONFIG_CRYPTO_RSA defaults to yes when FITIMAGE_SIGNATURE is selected so that existing configs continue to work. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- common/Kconfig | 1 - common/image-fit.c | 5 +++++ crypto/Kconfig | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 31360892ae..65850f68bd 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -59,7 +59,6 @@ config FITIMAGE select DIGEST config FITIMAGE_SIGNATURE - select CRYPTO_RSA bool config LOGBUF diff --git a/common/image-fit.c b/common/image-fit.c index 4a69049abc..6002440e7e 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -262,6 +262,11 @@ static int fit_check_rsa_signature(struct device_node *sig_node, const char *sig_value; int ret; + if (!IS_ENABLED(CONFIG_CRYPTO_RSA)) { + pr_err("RSA support is disabled, Cannot verify image\n"); + return -EOPNOTSUPP; + } + sig_value = of_get_property(sig_node, "value", &sig_len); if (!sig_value) { pr_err("signature value not found in %pOF\n", sig_node); diff --git a/crypto/Kconfig b/crypto/Kconfig index eeacd9ffb7..22faff5100 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -116,7 +116,8 @@ config CRYPTO_PBKDF2 bool config CRYPTO_RSA - bool + bool "RSA support" + default y if FITIMAGE_SIGNATURE config CRYPTO_RSA_BUILTIN_KEYS bool -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 18/19] crypto: make RSA a visible option 2024-08-01 5:57 ` [PATCH v2 18/19] crypto: make RSA a visible option Sascha Hauer @ 2024-08-05 10:19 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 10:19 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > With upcoming ECDSA support RSA won't be the only option for FIT image > verification anymore. Make CONFIG_CRYPTO_RSA visible so that the user > can choose. CONFIG_CRYPTO_RSA defaults to yes when FITIMAGE_SIGNATURE > is selected so that existing configs continue to work. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > common/Kconfig | 1 - > common/image-fit.c | 5 +++++ > crypto/Kconfig | 3 ++- > 3 files changed, 7 insertions(+), 2 deletions(-) > > diff --git a/common/Kconfig b/common/Kconfig > index 31360892ae..65850f68bd 100644 > --- a/common/Kconfig > +++ b/common/Kconfig > @@ -59,7 +59,6 @@ config FITIMAGE > select DIGEST > > config FITIMAGE_SIGNATURE > - select CRYPTO_RSA > bool > > config LOGBUF > diff --git a/common/image-fit.c b/common/image-fit.c > index 4a69049abc..6002440e7e 100644 > --- a/common/image-fit.c > +++ b/common/image-fit.c > @@ -262,6 +262,11 @@ static int fit_check_rsa_signature(struct device_node *sig_node, > const char *sig_value; > int ret; > > + if (!IS_ENABLED(CONFIG_CRYPTO_RSA)) { > + pr_err("RSA support is disabled, Cannot verify image\n"); > + return -EOPNOTSUPP; > + } > + > sig_value = of_get_property(sig_node, "value", &sig_len); > if (!sig_value) { > pr_err("signature value not found in %pOF\n", sig_node); > diff --git a/crypto/Kconfig b/crypto/Kconfig > index eeacd9ffb7..22faff5100 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -116,7 +116,8 @@ config CRYPTO_PBKDF2 > bool > > config CRYPTO_RSA > - bool > + bool "RSA support" > + default y if FITIMAGE_SIGNATURE > > config CRYPTO_RSA_BUILTIN_KEYS > bool -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* [PATCH v2 19/19] fit: Add ecdsa support 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (17 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 18/19] crypto: make RSA a visible option Sascha Hauer @ 2024-08-01 5:57 ` Sascha Hauer 2024-08-05 12:04 ` Ahmad Fatoum 2024-08-06 6:03 ` [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-01 5:57 UTC (permalink / raw) To: Barebox List This adds ECDSA signing support to the FIT image code. Previously we unconditionally called into rsa_verify() as this was the only option. Now with ECDSA support we first have to check the type of the signature, so we start evaluating the signature type in given in the FIT image and call rsa_verify() or ecdsa_verify() depending on it. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> --- common/image-fit.c | 112 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 18 deletions(-) diff --git a/common/image-fit.c b/common/image-fit.c index 6002440e7e..599d969a38 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -21,6 +21,7 @@ #include <linux/err.h> #include <stringlist.h> #include <rsa.h> +#include <ecdsa.h> #include <uncompress.h> #include <image-fit.h> @@ -253,13 +254,11 @@ static struct digest *fit_alloc_digest(struct device_node *sig_node, return digest; } -static int fit_check_rsa_signature(struct device_node *sig_node, - enum hash_algo algo, void *hash) +static int fit_check_rsa_signature(const void *signature, size_t sig_len, + enum hash_algo algo, void *hash, + const char *key_name) { const struct rsa_public_key *key; - const char *key_name = NULL; - int sig_len; - const char *sig_value; int ret; if (!IS_ENABLED(CONFIG_CRYPTO_RSA)) { @@ -267,17 +266,10 @@ static int fit_check_rsa_signature(struct device_node *sig_node, return -EOPNOTSUPP; } - sig_value = of_get_property(sig_node, "value", &sig_len); - if (!sig_value) { - pr_err("signature value not found in %pOF\n", sig_node); - return -EINVAL; - } - - of_property_read_string(sig_node, "key-name-hint", &key_name); if (key_name) { key = rsa_get_key(key_name); if (key) { - ret = rsa_verify(key, sig_value, sig_len, hash, algo); + ret = rsa_verify(key, signature, sig_len, hash, algo); if (!ret) goto ok; } @@ -287,20 +279,104 @@ static int fit_check_rsa_signature(struct device_node *sig_node, if (key_name && !strcmp(key->key_name_hint, key_name)) continue; - ret = rsa_verify(key, sig_value, sig_len, hash, algo); + ret = rsa_verify(key, signature, sig_len, hash, algo); if (!ret) goto ok; } - pr_err("image signature BAD\n"); + pr_err("image RSA signature BAD\n"); return -EBADMSG; ok: - pr_info("image signature OK\n"); + pr_info("image RSA signature OK\n"); return 0; } +static int fit_check_ecdsa_signature(const void *signature, size_t sig_len, + enum hash_algo algo, void *hash, + const char *key_name) +{ + const struct ecdsa_public_key *key; + int ret; + + if (!IS_ENABLED(CONFIG_CRYPTO_ECDSA)) { + pr_err("ECDSA support is disabled, Cannot verify image\n"); + return -EOPNOTSUPP; + } + + for_each_ecdsa_key(key) { + ret = ecdsa_verify(key, signature, sig_len, hash); + if (!ret) { + pr_info("image ECDSA signature OK\n"); + return 0; + } + } + + pr_err("image ECDSA signature BAD\n"); + + return -EBADMSG; +} + +struct crypto_algo { + const char *name; + int (*verify)(const void *signature, size_t sig_len, enum hash_algo algo, + void *hash, const char *key_name); +}; + +static struct crypto_algo crypto_algos[] = { + { + .name = "rsa2048", + .verify = fit_check_rsa_signature, + }, { + .name = "rsa3072", + .verify = fit_check_rsa_signature, + }, { + .name = "rsa4096", + .verify = fit_check_rsa_signature, + }, { + .name = "ecdsa256", + .verify = fit_check_ecdsa_signature, + }, +}; + +static int fit_check_signature(struct device_node *sig_node, + enum hash_algo algo, void *hash) +{ + int sig_len, i; + const char *sig_value; + const char *algo_name; + const char *key_name = NULL; + const char *str; + + sig_value = of_get_property(sig_node, "value", &sig_len); + if (!sig_value) { + pr_err("signature value not found in %pOF\n", sig_node); + return -EINVAL; + } + + of_property_read_string(sig_node, "key-name-hint", &key_name); + + if (of_property_read_string(sig_node, "algo", &algo_name)) { + pr_err("algo property not found\n"); + return -EINVAL; + } + + str = strchr(algo_name, ','); + if (!str) + return -EINVAL; + str++; + + for (i = 0; i < ARRAY_SIZE(crypto_algos); i++) { + struct crypto_algo *ca = &crypto_algos[i]; + + if (!strcmp(ca->name, str)) + return ca->verify(sig_value, sig_len, algo, hash, key_name); + } + + return -EINVAL; +} + /* * The consistency of the FTD structure was already checked by of_unflatten_dtb() */ @@ -346,7 +422,7 @@ static int fit_verify_signature(struct device_node *sig_node, const void *fit) hash = xzalloc(digest_length(digest)); digest_final(digest, hash); - ret = fit_check_rsa_signature(sig_node, algo, hash); + ret = fit_check_signature(sig_node, algo, hash); if (ret) goto out_free_hash; @@ -469,7 +545,7 @@ static int fit_image_verify_signature(struct fit_handle *handle, hash = xzalloc(digest_length(digest)); digest_final(digest, hash); - ret = fit_check_rsa_signature(sig_node, algo, hash); + ret = fit_check_signature(sig_node, algo, hash); free(hash); -- 2.39.2 ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 19/19] fit: Add ecdsa support 2024-08-01 5:57 ` [PATCH v2 19/19] fit: Add ecdsa support Sascha Hauer @ 2024-08-05 12:04 ` Ahmad Fatoum 0 siblings, 0 replies; 45+ messages in thread From: Ahmad Fatoum @ 2024-08-05 12:04 UTC (permalink / raw) To: Sascha Hauer, Barebox List On 01.08.24 07:57, Sascha Hauer wrote: > This adds ECDSA signing support to the FIT image code. > > Previously we unconditionally called into rsa_verify() as this was the > only option. Now with ECDSA support we first have to check the type of > the signature, so we start evaluating the signature type in given in the > FIT image and call rsa_verify() or ecdsa_verify() depending on it. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > common/image-fit.c | 112 +++++++++++++++++++++++++++++++++++++-------- > 1 file changed, 94 insertions(+), 18 deletions(-) > > diff --git a/common/image-fit.c b/common/image-fit.c > index 6002440e7e..599d969a38 100644 > --- a/common/image-fit.c > +++ b/common/image-fit.c > @@ -21,6 +21,7 @@ > #include <linux/err.h> > #include <stringlist.h> > #include <rsa.h> > +#include <ecdsa.h> > #include <uncompress.h> > #include <image-fit.h> > > @@ -253,13 +254,11 @@ static struct digest *fit_alloc_digest(struct device_node *sig_node, > return digest; > } > > -static int fit_check_rsa_signature(struct device_node *sig_node, > - enum hash_algo algo, void *hash) > +static int fit_check_rsa_signature(const void *signature, size_t sig_len, > + enum hash_algo algo, void *hash, > + const char *key_name) > { > const struct rsa_public_key *key; > - const char *key_name = NULL; > - int sig_len; > - const char *sig_value; > int ret; > > if (!IS_ENABLED(CONFIG_CRYPTO_RSA)) { > @@ -267,17 +266,10 @@ static int fit_check_rsa_signature(struct device_node *sig_node, > return -EOPNOTSUPP; > } > > - sig_value = of_get_property(sig_node, "value", &sig_len); > - if (!sig_value) { > - pr_err("signature value not found in %pOF\n", sig_node); > - return -EINVAL; > - } > - > - of_property_read_string(sig_node, "key-name-hint", &key_name); > if (key_name) { > key = rsa_get_key(key_name); > if (key) { > - ret = rsa_verify(key, sig_value, sig_len, hash, algo); > + ret = rsa_verify(key, signature, sig_len, hash, algo); > if (!ret) > goto ok; > } > @@ -287,20 +279,104 @@ static int fit_check_rsa_signature(struct device_node *sig_node, > if (key_name && !strcmp(key->key_name_hint, key_name)) > continue; > > - ret = rsa_verify(key, sig_value, sig_len, hash, algo); > + ret = rsa_verify(key, signature, sig_len, hash, algo); > if (!ret) > goto ok; > } > > - pr_err("image signature BAD\n"); > + pr_err("image RSA signature BAD\n"); > > return -EBADMSG; > ok: > - pr_info("image signature OK\n"); > + pr_info("image RSA signature OK\n"); > > return 0; > } > > +static int fit_check_ecdsa_signature(const void *signature, size_t sig_len, > + enum hash_algo algo, void *hash, > + const char *key_name) > +{ > + const struct ecdsa_public_key *key; > + int ret; > + > + if (!IS_ENABLED(CONFIG_CRYPTO_ECDSA)) { > + pr_err("ECDSA support is disabled, Cannot verify image\n"); > + return -EOPNOTSUPP; > + } > + > + for_each_ecdsa_key(key) { > + ret = ecdsa_verify(key, signature, sig_len, hash); > + if (!ret) { > + pr_info("image ECDSA signature OK\n"); > + return 0; > + } > + } > + > + pr_err("image ECDSA signature BAD\n"); > + > + return -EBADMSG; > +} > + > +struct crypto_algo { > + const char *name; > + int (*verify)(const void *signature, size_t sig_len, enum hash_algo algo, > + void *hash, const char *key_name); > +}; > + > +static struct crypto_algo crypto_algos[] = { > + { > + .name = "rsa2048", > + .verify = fit_check_rsa_signature, > + }, { > + .name = "rsa3072", > + .verify = fit_check_rsa_signature, > + }, { > + .name = "rsa4096", > + .verify = fit_check_rsa_signature, > + }, { > + .name = "ecdsa256", > + .verify = fit_check_ecdsa_signature, > + }, > +}; > + > +static int fit_check_signature(struct device_node *sig_node, > + enum hash_algo algo, void *hash) > +{ > + int sig_len, i; > + const char *sig_value; > + const char *algo_name; > + const char *key_name = NULL; > + const char *str; > + > + sig_value = of_get_property(sig_node, "value", &sig_len); > + if (!sig_value) { > + pr_err("signature value not found in %pOF\n", sig_node); > + return -EINVAL; > + } > + > + of_property_read_string(sig_node, "key-name-hint", &key_name); > + > + if (of_property_read_string(sig_node, "algo", &algo_name)) { > + pr_err("algo property not found\n"); > + return -EINVAL; > + } > + > + str = strchr(algo_name, ','); > + if (!str) > + return -EINVAL; > + str++; > + > + for (i = 0; i < ARRAY_SIZE(crypto_algos); i++) { > + struct crypto_algo *ca = &crypto_algos[i]; > + > + if (!strcmp(ca->name, str)) > + return ca->verify(sig_value, sig_len, algo, hash, key_name); > + } > + > + return -EINVAL; > +} > + > /* > * The consistency of the FTD structure was already checked by of_unflatten_dtb() > */ > @@ -346,7 +422,7 @@ static int fit_verify_signature(struct device_node *sig_node, const void *fit) > hash = xzalloc(digest_length(digest)); > digest_final(digest, hash); > > - ret = fit_check_rsa_signature(sig_node, algo, hash); > + ret = fit_check_signature(sig_node, algo, hash); > if (ret) > goto out_free_hash; > > @@ -469,7 +545,7 @@ static int fit_image_verify_signature(struct fit_handle *handle, > hash = xzalloc(digest_length(digest)); > digest_final(digest, hash); > > - ret = fit_check_rsa_signature(sig_node, algo, hash); > + ret = fit_check_signature(sig_node, algo, hash); > > free(hash); > -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 00/19] Add ECDSA support for FIT image verification 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer ` (18 preceding siblings ...) 2024-08-01 5:57 ` [PATCH v2 19/19] fit: Add ecdsa support Sascha Hauer @ 2024-08-06 6:03 ` Sascha Hauer 2024-08-06 6:07 ` Sascha Hauer 19 siblings, 1 reply; 45+ messages in thread From: Sascha Hauer @ 2024-08-06 6:03 UTC (permalink / raw) To: Barebox List, Sascha Hauer On Thu, 01 Aug 2024 07:57:18 +0200, Sascha Hauer wrote: > This series implements ECDSA signature verification for FIT images. > The ECDSA code itself is taken from the Kernel. Currently only supported > way to specify a ECDSA key is to compile it into the binary using > CONFIG_CRYPTO_ECDSA_KEY, taking it from a device tree is not ye > supported. > > Changes since v1: > - better split up rsatoc patches > - keep engine support around in rsatoc as it is still needed in many > cases > - Add more cleanup to rsatoc > > [...] Applied, thanks! [01/19] errno: include string for EOPNOTSUPP https://git.pengutronix.de/cgit/barebox/commit/?id=1ad1a884407f (link may not be stable) [02/19] rsatoc: disable deprecated function warnings https://git.pengutronix.de/cgit/barebox/commit/?id=d64d733d2451 (link may not be stable) [03/19] rsatoc: remove unnecessary function call https://git.pengutronix.de/cgit/barebox/commit/?id=42731deb592f (link may not be stable) [04/19] rsatoc: pass EVP_PKEY around https://git.pengutronix.de/cgit/barebox/commit/?id=b1fef1396772 (link may not be stable) [05/19] rsatoc: rename rsa_err() to openssl_error() https://git.pengutronix.de/cgit/barebox/commit/?id=5206d3b61418 (link may not be stable) [06/19] rsatoc: move engine initialization to engine_get_pub_key() https://git.pengutronix.de/cgit/barebox/commit/?id=89d32ef83ecd (link may not be stable) [07/19] rsatoc: cleanup error handling https://git.pengutronix.de/cgit/barebox/commit/?id=c99779284ce5 (link may not be stable) [08/19] rsatoc: remove unnecessary error check https://git.pengutronix.de/cgit/barebox/commit/?id=2ec045398f6d (link may not be stable) [09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params https://git.pengutronix.de/cgit/barebox/commit/?id=cc0b8a2e7606 (link may not be stable) [10/19] rsatoc: check error value of gen_key() https://git.pengutronix.de/cgit/barebox/commit/?id=6df30149362d (link may not be stable) [11/19] rsatoc: rename to keytoc https://git.pengutronix.de/cgit/barebox/commit/?id=7b51f76a4534 (link may not be stable) [12/19] keytoc: add ecdsa support https://git.pengutronix.de/cgit/barebox/commit/?id=994f3df141f5 (link may not be stable) [13/19] keytoc: Let openssl_error() take a format string https://git.pengutronix.de/cgit/barebox/commit/?id=73a0f34fddc7 (link may not be stable) [14/19] keytoc: clarify error messages https://git.pengutronix.de/cgit/barebox/commit/?id=cfd2a8f1fc19 (link may not be stable) [15/19] malloc: implement free_sensitive() (no commit info) [16/19] Add elliptic curve cryptography (ECC) helper functions (no commit info) [17/19] crypto: add ECDSA support (no commit info) [18/19] crypto: make RSA a visible option (no commit info) [19/19] fit: Add ecdsa support (no commit info) Best regards, -- Sascha Hauer <s.hauer@pengutronix.de> ^ permalink raw reply [flat|nested] 45+ messages in thread
* Re: [PATCH v2 00/19] Add ECDSA support for FIT image verification 2024-08-06 6:03 ` [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer @ 2024-08-06 6:07 ` Sascha Hauer 0 siblings, 0 replies; 45+ messages in thread From: Sascha Hauer @ 2024-08-06 6:07 UTC (permalink / raw) To: Barebox List On Tue, Aug 06, 2024 at 08:03:48AM +0200, Sascha Hauer wrote: > > On Thu, 01 Aug 2024 07:57:18 +0200, Sascha Hauer wrote: > > This series implements ECDSA signature verification for FIT images. > > The ECDSA code itself is taken from the Kernel. Currently only supported > > way to specify a ECDSA key is to compile it into the binary using > > CONFIG_CRYPTO_ECDSA_KEY, taking it from a device tree is not ye > > supported. > > > > Changes since v1: > > - better split up rsatoc patches > > - keep engine support around in rsatoc as it is still needed in many > > cases > > - Add more cleanup to rsatoc > > > > [...] > > Applied, thanks! > > [01/19] errno: include string for EOPNOTSUPP > https://git.pengutronix.de/cgit/barebox/commit/?id=1ad1a884407f (link may not be stable) > [02/19] rsatoc: disable deprecated function warnings > https://git.pengutronix.de/cgit/barebox/commit/?id=d64d733d2451 (link may not be stable) > [03/19] rsatoc: remove unnecessary function call > https://git.pengutronix.de/cgit/barebox/commit/?id=42731deb592f (link may not be stable) > [04/19] rsatoc: pass EVP_PKEY around > https://git.pengutronix.de/cgit/barebox/commit/?id=b1fef1396772 (link may not be stable) > [05/19] rsatoc: rename rsa_err() to openssl_error() > https://git.pengutronix.de/cgit/barebox/commit/?id=5206d3b61418 (link may not be stable) > [06/19] rsatoc: move engine initialization to engine_get_pub_key() > https://git.pengutronix.de/cgit/barebox/commit/?id=89d32ef83ecd (link may not be stable) > [07/19] rsatoc: cleanup error handling > https://git.pengutronix.de/cgit/barebox/commit/?id=c99779284ce5 (link may not be stable) > [08/19] rsatoc: remove unnecessary error check > https://git.pengutronix.de/cgit/barebox/commit/?id=2ec045398f6d (link may not be stable) > [09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params > https://git.pengutronix.de/cgit/barebox/commit/?id=cc0b8a2e7606 (link may not be stable) > [10/19] rsatoc: check error value of gen_key() > https://git.pengutronix.de/cgit/barebox/commit/?id=6df30149362d (link may not be stable) > [11/19] rsatoc: rename to keytoc > https://git.pengutronix.de/cgit/barebox/commit/?id=7b51f76a4534 (link may not be stable) > [12/19] keytoc: add ecdsa support > https://git.pengutronix.de/cgit/barebox/commit/?id=994f3df141f5 (link may not be stable) > [13/19] keytoc: Let openssl_error() take a format string > https://git.pengutronix.de/cgit/barebox/commit/?id=73a0f34fddc7 (link may not be stable) > [14/19] keytoc: clarify error messages > https://git.pengutronix.de/cgit/barebox/commit/?id=cfd2a8f1fc19 (link may not be stable) Really I applied up to this patch with Ahmads comments applied. The remaining ones need some more work which I'll do later. Sascha -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 45+ messages in thread
end of thread, other threads:[~2024-08-06 9:14 UTC | newest] Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2024-08-01 5:57 [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer 2024-08-01 5:57 ` [PATCH v2 01/19] errno: include string for EOPNOTSUPP Sascha Hauer 2024-08-05 9:28 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 02/19] rsatoc: disable deprecated function warnings Sascha Hauer 2024-08-05 9:29 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 03/19] rsatoc: remove unnecessary function call Sascha Hauer 2024-08-05 9:29 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 04/19] rsatoc: pass EVP_PKEY around Sascha Hauer 2024-08-05 9:35 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 05/19] rsatoc: rename rsa_err() to openssl_error() Sascha Hauer 2024-08-05 9:37 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 06/19] rsatoc: move engine initialization to engine_get_pub_key() Sascha Hauer 2024-08-05 9:47 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 07/19] rsatoc: cleanup error handling Sascha Hauer 2024-08-05 9:54 ` Ahmad Fatoum 2024-08-05 10:07 ` Sascha Hauer 2024-08-01 5:57 ` [PATCH v2 08/19] rsatoc: remove unnecessary error check Sascha Hauer 2024-08-05 9:56 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 09/19] rsatoc: use non deprecated openssl functions to retrieve RSA params Sascha Hauer 2024-08-05 10:02 ` Ahmad Fatoum 2024-08-05 10:29 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 10/19] rsatoc: check error value of gen_key() Sascha Hauer 2024-08-05 10:03 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 11/19] rsatoc: rename to keytoc Sascha Hauer 2024-08-05 10:05 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 12/19] keytoc: add ecdsa support Sascha Hauer 2024-08-05 11:04 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 13/19] keytoc: Let openssl_error() take a format string Sascha Hauer 2024-08-05 10:22 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 14/19] keytoc: clarify error messages Sascha Hauer 2024-08-05 10:06 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 15/19] malloc: implement free_sensitive() Sascha Hauer 2024-08-05 10:17 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 16/19] Add elliptic curve cryptography (ECC) helper functions Sascha Hauer 2024-08-05 11:32 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 17/19] crypto: add ECDSA support Sascha Hauer 2024-08-05 11:57 ` Ahmad Fatoum 2024-08-05 12:44 ` Sascha Hauer 2024-08-06 9:13 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 18/19] crypto: make RSA a visible option Sascha Hauer 2024-08-05 10:19 ` Ahmad Fatoum 2024-08-01 5:57 ` [PATCH v2 19/19] fit: Add ecdsa support Sascha Hauer 2024-08-05 12:04 ` Ahmad Fatoum 2024-08-06 6:03 ` [PATCH v2 00/19] Add ECDSA support for FIT image verification Sascha Hauer 2024-08-06 6:07 ` Sascha Hauer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox