Path: blob/main/crypto/libecc/src/sig/fuzzing_ecdsa.c
39535 views
/*1* Copyright (C) 2017 - This file is part of libecc project2*3* Authors:4* Ryad BENADJILA <[email protected]>5* Arnaud EBALARD <[email protected]>6* Jean-Pierre FLORI <[email protected]>7*8* Contributors:9* Nicolas VIVET <[email protected]>10* Karim KHALFALLAH <[email protected]>11*12* This software is licensed under a dual BSD and GPL v2 license.13* See LICENSE file at the root folder of the project.14*/15#include <libecc/lib_ecc_config.h>16#if defined(WITH_SIG_ECDSA) && defined(USE_CRYPTOFUZZ)1718#include <libecc/nn/nn_rand.h>19#include <libecc/nn/nn_mul.h>20#include <libecc/nn/nn_logical.h>2122#include <libecc/sig/sig_algs_internal.h>23#include <libecc/sig/ec_key.h>24#include <libecc/utils/utils.h>25#ifdef VERBOSE_INNER_VALUES26#define EC_SIG_ALG "ECDSA"27#endif28#include <libecc/utils/dbg_sig.h>2930/* NOTE: the following versions of ECDSA are "raw" with31* no hash functions and nonce override. They are DANGEROUS and32* should NOT be used in production mode! They are however useful33* for corner cases tests and fuzzing.34*/3536#define ECDSA_SIGN_MAGIC ((word_t)(0x80299a2bf630945bULL))37#define ECDSA_SIGN_CHECK_INITIALIZED(A, ret, err) \38MUST_HAVE((((void *)(A)) != NULL) && ((A)->magic == ECDSA_SIGN_MAGIC), ret, err)3940int ecdsa_sign_raw(struct ec_sign_context *ctx, const u8 *input, u8 inputlen, u8 *sig, u8 siglen, const u8 *nonce, u8 noncelen)41{42const ec_priv_key *priv_key;43prj_pt_src_t G;44/* NOTE: hash here is not really a hash ... */45u8 hash[LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8))];46bitcnt_t rshift, q_bit_len;47prj_pt kG;48nn_src_t q, x;49u8 hsize, q_len;50int ret, iszero, cmp;51nn k, r, e, tmp, s, kinv;52#ifdef USE_SIG_BLINDING53/* b is the blinding mask */54nn b;55b.magic = WORD(0);56#endif57k.magic = r.magic = e.magic = WORD(0);58tmp.magic = s.magic = kinv.magic = WORD(0);59kG.magic = WORD(0);6061/*62* First, verify context has been initialized and private63* part too. This guarantees the context is an ECDSA64* signature one and we do not finalize() before init().65*/66ret = sig_sign_check_initialized(ctx); EG(ret, err);67ECDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.ecdsa), ret, err);68MUST_HAVE((input != NULL) && (sig != NULL), ret, err);6970/* Zero init out poiny */71ret = local_memset(&kG, 0, sizeof(prj_pt)); EG(ret, err);7273/* Make things more readable */74priv_key = &(ctx->key_pair->priv_key);75q = &(priv_key->params->ec_gen_order);76q_bit_len = priv_key->params->ec_gen_order_bitlen;77G = &(priv_key->params->ec_gen);78q_len = (u8)BYTECEIL(q_bit_len);79x = &(priv_key->x);80hsize = inputlen;8182dbg_nn_print("p", &(priv_key->params->ec_fp.p));83dbg_nn_print("q", &(priv_key->params->ec_gen_order));84dbg_priv_key_print("x", priv_key);85dbg_ec_point_print("G", &(priv_key->params->ec_gen));86dbg_pub_key_print("Y", &(ctx->key_pair->pub_key));8788/* Check given signature buffer length has the expected size */89MUST_HAVE((siglen == ECDSA_SIGLEN(q_bit_len)), ret, err);9091/* 1. Compute h = H(m) */92/* NOTE: here we have raw ECDSA, this is the raw input */93/* NOTE: the MUST_HAVE is protected by a preprocessing check94* to avoid -Werror=type-limits errors:95* "error: comparison is always true due to limited range of data type"96*/97#if LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8)) < 25598MUST_HAVE(((u32)inputlen <= sizeof(hash)), ret, err);99#endif100ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);101ret = local_memcpy(hash, input, hsize); EG(ret, err);102103dbg_buf_print("h", hash, hsize);104105/*106* 2. If |h| > bitlen(q), set h to bitlen(q)107* leftmost bits of h.108*109* Note that it's easier to check if the truncation has110* to be done here but only implement it using a logical111* shift at the beginning of step 3. below once the hash112* has been converted to an integer.113*/114rshift = 0;115if ((hsize * 8) > q_bit_len) {116rshift = (bitcnt_t)((hsize * 8) - q_bit_len);117}118119/*120* 3. Compute e = OS2I(h) mod q, i.e. by converting h to an121* integer and reducing it mod q122*/123ret = nn_init_from_buf(&e, hash, hsize); EG(ret, err);124ret = local_memset(hash, 0, hsize); EG(ret, err);125dbg_nn_print("h initial import as nn", &e);126if (rshift) {127ret = nn_rshift_fixedlen(&e, &e, rshift); EG(ret, err);128}129dbg_nn_print("h final import as nn", &e);130ret = nn_mod(&e, &e, q); EG(ret, err);131dbg_nn_print("e", &e);132133/*134NOTE: the restart label is removed in CRYPTOFUZZ mode as135we trigger MUST_HAVE instead of restarting in this mode.136restart:137*/138/* 4. get a random value k in ]0,q[ */139/* NOTE: copy our input nonce if not NULL */140if(nonce != NULL){141MUST_HAVE((noncelen <= (u8)(BYTECEIL(q_bit_len))), ret, err);142ret = nn_init_from_buf(&k, nonce, noncelen); EG(ret, err);143}144else{145ret = ctx->rand(&k, q); EG(ret, err);146}147dbg_nn_print("k", &k);148149#ifdef USE_SIG_BLINDING150/* Note: if we use blinding, r and e are multiplied by151* a random value b in ]0,q[ */152ret = nn_get_random_mod(&b, q); EG(ret, err);153dbg_nn_print("b", &b);154#endif /* USE_SIG_BLINDING */155156157/* 5. Compute W = (W_x,W_y) = kG */158#ifdef USE_SIG_BLINDING159ret = prj_pt_mul_blind(&kG, &k, G); EG(ret, err);160#else161ret = prj_pt_mul(&kG, &k, G); EG(ret, err);162#endif /* USE_SIG_BLINDING */163ret = prj_pt_unique(&kG, &kG); EG(ret, err);164165dbg_nn_print("W_x", &(kG.X.fp_val));166dbg_nn_print("W_y", &(kG.Y.fp_val));167168/* 6. Compute r = W_x mod q */169ret = nn_mod(&r, &(kG.X.fp_val), q); EG(ret, err);170dbg_nn_print("r", &r);171172/* 7. If r is 0, restart the process at step 4. */173/* NOTE: for the CRYPTOFUZZ mode, we do not restart174* the procedure but throw an assert exception instead.175*/176ret = nn_iszero(&r, &iszero); EG(ret, err);177MUST_HAVE((!iszero), ret, err);178179/* Export r */180ret = nn_export_to_buf(sig, q_len, &r); EG(ret, err);181182#ifdef USE_SIG_BLINDING183/* Blind r with b */184ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err);185186/* Blind the message e */187ret = nn_mod_mul(&e, &e, &b, q); EG(ret, err);188#endif /* USE_SIG_BLINDING */189190/* tmp = xr mod q */191ret = nn_mod_mul(&tmp, x, &r, q); EG(ret, err);192dbg_nn_print("x*r mod q", &tmp);193194/* 8. If e == rx, restart the process at step 4. */195/* NOTE: for the CRYPTOFUZZ mode, we do not restart196* the procedure but throw an assert exception instead.197*/198ret = nn_cmp(&e, &tmp, &cmp); EG(ret, err);199MUST_HAVE(cmp, ret, err);200201/* 9. Compute s = k^-1 * (xr + e) mod q */202203/* tmp2 = (e + xr) mod q */204ret = nn_mod_add(&tmp, &tmp, &e, q); EG(ret, err);205dbg_nn_print("(xr + e) mod q", &tmp);206207#ifdef USE_SIG_BLINDING208/* In case of blinding, we compute (b*k)^-1, and209* b^-1 will automatically unblind (r*x) in the following210*/211ret = nn_mod_mul(&k, &k, &b, q); EG(ret, err);212#endif213/* Compute k^-1 mod q */214/* NOTE: we use Fermat's little theorem inversion for215* constant time here. This is possible since q is prime.216*/217ret = nn_modinv_fermat(&kinv, &k, q); EG(ret, err);218219dbg_nn_print("k^-1 mod q", &kinv);220221/* s = k^-1 * tmp2 mod q */222ret = nn_mod_mul(&s, &tmp, &kinv, q); EG(ret, err);223224dbg_nn_print("s", &s);225226/* 10. If s is 0, restart the process at step 4. */227/* NOTE: for the CRYPTOFUZZ mode, we do not restart228* the procedure but throw an assert exception instead.229*/230ret = nn_iszero(&s, &iszero); EG(ret, err);231MUST_HAVE((!iszero), ret, err);232233/* 11. return (r,s) */234ret = nn_export_to_buf(sig + q_len, q_len, &s);235236err:237238nn_uninit(&r);239nn_uninit(&s);240nn_uninit(&e);241nn_uninit(&tmp);242nn_uninit(&k);243nn_uninit(&kinv);244prj_pt_uninit(&kG);245246/*247* We can now clear data part of the context. This will clear248* magic and avoid further reuse of the whole context.249*/250if(ctx != NULL){251IGNORE_RET_VAL(local_memset(&(ctx->sign_data.ecdsa), 0, sizeof(ecdsa_sign_data)));252}253254/* Clean what remains on the stack */255PTR_NULLIFY(priv_key);256PTR_NULLIFY(G);257PTR_NULLIFY(q);258PTR_NULLIFY(x);259VAR_ZEROIFY(q_len);260VAR_ZEROIFY(q_bit_len);261VAR_ZEROIFY(rshift);262VAR_ZEROIFY(hsize);263264#ifdef USE_SIG_BLINDING265nn_uninit(&b);266#endif /* USE_SIG_BLINDING */267268return ret;269}270271/******************************/272#define ECDSA_VERIFY_MAGIC ((word_t)(0x5155fe73e7fd51beULL))273#define ECDSA_VERIFY_CHECK_INITIALIZED(A, ret, err) \274MUST_HAVE((((void *)(A)) != NULL) && ((A)->magic == ECDSA_VERIFY_MAGIC), ret, err)275276int ecdsa_verify_raw(struct ec_verify_context *ctx, const u8 *input, u8 inputlen)277{278prj_pt uG, vY;279prj_pt_t W_prime;280nn e, sinv, uv, r_prime;281prj_pt_src_t G, Y;282/* NOTE: hash here is not really a hash ... */283u8 hash[LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8))];284bitcnt_t rshift, q_bit_len;285nn_src_t q;286nn *s, *r;287u8 hsize;288int ret, iszero, cmp;289290e.magic = sinv.magic = uv.magic = r_prime.magic = WORD(0);291uG.magic = vY.magic = WORD(0);292293/* NOTE: we reuse uG for W_prime to optimize local variables */294W_prime = &uG;295296/*297* First, verify context has been initialized and public298* part too. This guarantees the context is an ECDSA299* verification one and we do not finalize() before init().300*/301ret = sig_verify_check_initialized(ctx); EG(ret, err);302ECDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.ecdsa), ret, err);303MUST_HAVE((input != NULL), ret, err);304305/* Zero init points */306ret = local_memset(&uG, 0, sizeof(prj_pt)); EG(ret, err);307ret = local_memset(&vY, 0, sizeof(prj_pt)); EG(ret, err);308309/* Make things more readable */310G = &(ctx->pub_key->params->ec_gen);311Y = &(ctx->pub_key->y);312q = &(ctx->pub_key->params->ec_gen_order);313q_bit_len = ctx->pub_key->params->ec_gen_order_bitlen;314hsize = inputlen;315r = &(ctx->verify_data.ecdsa.r);316s = &(ctx->verify_data.ecdsa.s);317318/* 2. Compute h = H(m) */319/* NOTE: here we have raw ECDSA, this is the raw input */320MUST_HAVE((input != NULL), ret, err);321/* NOTE: the MUST_HAVE is protected by a preprocessing check322* to avoid -Werror=type-limits errors:323* "error: comparison is always true due to limited range of data type"324*/325#if LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8)) < 255326MUST_HAVE(((u32)inputlen <= sizeof(hash)), ret, err);327#endif328329ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);330ret = local_memcpy(hash, input, hsize); EG(ret, err);331332dbg_buf_print("h = H(m)", hash, hsize);333334/*335* 3. If |h| > bitlen(q), set h to bitlen(q)336* leftmost bits of h.337*338* Note that it's easier to check here if the truncation339* needs to be done but implement it using a logical340* shift at the beginning of step 3. below once the hash341* has been converted to an integer.342*/343rshift = 0;344if ((hsize * 8) > q_bit_len) {345rshift = (bitcnt_t)((hsize * 8) - q_bit_len);346}347348/*349* 4. Compute e = OS2I(h) mod q, by converting h to an integer350* and reducing it mod q351*/352ret = nn_init_from_buf(&e, hash, hsize); EG(ret, err);353ret = local_memset(hash, 0, hsize); EG(ret, err);354dbg_nn_print("h initial import as nn", &e);355if (rshift) {356ret = nn_rshift_fixedlen(&e, &e, rshift); EG(ret, err);357}358dbg_nn_print("h final import as nn", &e);359360ret = nn_mod(&e, &e, q); EG(ret, err);361dbg_nn_print("e", &e);362363/* Compute s^-1 mod q */364ret = nn_modinv(&sinv, s, q); EG(ret, err);365dbg_nn_print("s", s);366dbg_nn_print("sinv", &sinv);367nn_uninit(s);368369/* 5. Compute u = (s^-1)e mod q */370ret = nn_mod_mul(&uv, &e, &sinv, q); EG(ret, err);371dbg_nn_print("u = (s^-1)e mod q", &uv);372ret = prj_pt_mul(&uG, &uv, G); EG(ret, err);373374/* 6. Compute v = (s^-1)r mod q */375ret = nn_mod_mul(&uv, r, &sinv, q); EG(ret, err);376dbg_nn_print("v = (s^-1)r mod q", &uv);377ret = prj_pt_mul(&vY, &uv, Y); EG(ret, err);378379/* 7. Compute W' = uG + vY */380ret = prj_pt_add(W_prime, &uG, &vY); EG(ret, err);381382/* 8. If W' is the point at infinity, reject the signature. */383ret = prj_pt_iszero(W_prime, &iszero); EG(ret, err);384MUST_HAVE((!iszero), ret, err);385386/* 9. Compute r' = W'_x mod q */387ret = prj_pt_unique(W_prime, W_prime); EG(ret, err);388dbg_nn_print("W'_x", &(W_prime->X.fp_val));389dbg_nn_print("W'_y", &(W_prime->Y.fp_val));390ret = nn_mod(&r_prime, &(W_prime->X.fp_val), q); EG(ret, err);391392/* 10. Accept the signature if and only if r equals r' */393ret = nn_cmp(&r_prime, r, &cmp); EG(ret, err);394ret = (cmp != 0) ? -1 : 0;395396err:397nn_uninit(&r_prime);398nn_uninit(&uv);399nn_uninit(&e);400nn_uninit(&sinv);401prj_pt_uninit(&uG);402prj_pt_uninit(&vY);403404/*405* We can now clear data part of the context. This will clear406* magic and avoid further reuse of the whole context.407*/408if(ctx != NULL){409IGNORE_RET_VAL(local_memset(&(ctx->verify_data.ecdsa), 0, sizeof(ecdsa_verify_data)));410}411412/* Clean what remains on the stack */413PTR_NULLIFY(W_prime);414PTR_NULLIFY(G);415PTR_NULLIFY(Y);416VAR_ZEROIFY(rshift);417VAR_ZEROIFY(q_bit_len);418PTR_NULLIFY(q);419PTR_NULLIFY(s);420PTR_NULLIFY(r);421VAR_ZEROIFY(hsize);422423return ret;424}425426427#else /* WITH_SIG_ECDSA && USE_CRYPTOFUZZ */428429/*430* Dummy definition to avoid the empty translation unit ISO C warning431*/432typedef int dummy;433#endif /* WITH_SIG_ECDSA */434435436