1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project
3*f0865ec9SKyle Evans *
4*f0865ec9SKyle Evans * Authors:
5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8*f0865ec9SKyle Evans *
9*f0865ec9SKyle Evans * Contributors:
10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12*f0865ec9SKyle Evans *
13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license.
14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project.
15*f0865ec9SKyle Evans */
16*f0865ec9SKyle Evans #include <libecc/lib_ecc_config.h>
17*f0865ec9SKyle Evans #if defined(WITH_SIG_ECRDSA) && defined(USE_CRYPTOFUZZ)
18*f0865ec9SKyle Evans
19*f0865ec9SKyle Evans #include <libecc/nn/nn_rand.h>
20*f0865ec9SKyle Evans #include <libecc/nn/nn_mul.h>
21*f0865ec9SKyle Evans #include <libecc/nn/nn_logical.h>
22*f0865ec9SKyle Evans
23*f0865ec9SKyle Evans #include <libecc/sig/sig_algs_internal.h>
24*f0865ec9SKyle Evans #include <libecc/sig/ec_key.h>
25*f0865ec9SKyle Evans #include <libecc/utils/utils.h>
26*f0865ec9SKyle Evans #ifdef VERBOSE_INNER_VALUES
27*f0865ec9SKyle Evans #define EC_SIG_ALG "ECRDSA"
28*f0865ec9SKyle Evans #endif
29*f0865ec9SKyle Evans #include <libecc/utils/dbg_sig.h>
30*f0865ec9SKyle Evans
31*f0865ec9SKyle Evans /* NOTE: the following versions of ECRDSA are "raw" with
32*f0865ec9SKyle Evans * no hash functions and nonce override. They are DANGEROUS and
33*f0865ec9SKyle Evans * should NOT be used in production mode! They are however useful
34*f0865ec9SKyle Evans * for corner cases tests and fuzzing.
35*f0865ec9SKyle Evans */
36*f0865ec9SKyle Evans
37*f0865ec9SKyle Evans /*
38*f0865ec9SKyle Evans * NOTE: ISO/IEC 14888-3 standard seems to diverge from the existing implementations
39*f0865ec9SKyle Evans * of ECRDSA when treating the message hash, and from the examples of certificates provided
40*f0865ec9SKyle Evans * in RFC 7091 and draft-deremin-rfc4491-bis. While in ISO/IEC 14888-3 it is explicitely asked
41*f0865ec9SKyle Evans * to proceed with the hash of the message as big endian, the RFCs derived from the Russian
42*f0865ec9SKyle Evans * standard expect the hash value to be treated as little endian when importing it as an integer
43*f0865ec9SKyle Evans * (this discrepancy is exhibited and confirmed by test vectors present in ISO/IEC 14888-3, and
44*f0865ec9SKyle Evans * by X.509 certificates present in the RFCs). This seems (to be confirmed) to be a discrepancy of
45*f0865ec9SKyle Evans * ISO/IEC 14888-3 algorithm description that must be fixed there.
46*f0865ec9SKyle Evans *
47*f0865ec9SKyle Evans * In order to be conservative, libecc uses the Russian standard behavior as expected to be in line with
48*f0865ec9SKyle Evans * other implemetations, but keeps the ISO/IEC 14888-3 behavior if forced/asked by the user using
49*f0865ec9SKyle Evans * the USE_ISO14888_3_ECRDSA toggle. This allows to keep backward compatibility with previous versions of the
50*f0865ec9SKyle Evans * library if needed.
51*f0865ec9SKyle Evans *
52*f0865ec9SKyle Evans */
53*f0865ec9SKyle Evans #ifndef USE_ISO14888_3_ECRDSA
54*f0865ec9SKyle Evans /* Reverses the endiannes of a buffer in place */
_reverse_endianness(u8 * buf,u16 buf_size)55*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int _reverse_endianness(u8 *buf, u16 buf_size)
56*f0865ec9SKyle Evans {
57*f0865ec9SKyle Evans u16 i;
58*f0865ec9SKyle Evans u8 tmp;
59*f0865ec9SKyle Evans int ret;
60*f0865ec9SKyle Evans
61*f0865ec9SKyle Evans MUST_HAVE((buf != NULL), ret, err);
62*f0865ec9SKyle Evans
63*f0865ec9SKyle Evans if(buf_size > 1){
64*f0865ec9SKyle Evans for(i = 0; i < (buf_size / 2); i++){
65*f0865ec9SKyle Evans tmp = buf[i];
66*f0865ec9SKyle Evans buf[i] = buf[buf_size - 1 - i];
67*f0865ec9SKyle Evans buf[buf_size - 1 - i] = tmp;
68*f0865ec9SKyle Evans }
69*f0865ec9SKyle Evans }
70*f0865ec9SKyle Evans
71*f0865ec9SKyle Evans ret = 0;
72*f0865ec9SKyle Evans err:
73*f0865ec9SKyle Evans return ret;
74*f0865ec9SKyle Evans }
75*f0865ec9SKyle Evans #endif
76*f0865ec9SKyle Evans
77*f0865ec9SKyle Evans #define ECRDSA_SIGN_MAGIC ((word_t)(0xcc97bbc8ada8973cULL))
78*f0865ec9SKyle Evans #define ECRDSA_SIGN_CHECK_INITIALIZED(A, ret, err) \
79*f0865ec9SKyle Evans MUST_HAVE((((const void *)(A)) != NULL) && \
80*f0865ec9SKyle Evans ((A)->magic == ECRDSA_SIGN_MAGIC), ret, err)
81*f0865ec9SKyle Evans
ecrdsa_sign_raw(struct ec_sign_context * ctx,const u8 * input,u8 inputlen,u8 * sig,u8 siglen,const u8 * nonce,u8 noncelen)82*f0865ec9SKyle Evans int ecrdsa_sign_raw(struct ec_sign_context *ctx, const u8 *input, u8 inputlen, u8 *sig, u8 siglen, const u8 *nonce, u8 noncelen)
83*f0865ec9SKyle Evans {
84*f0865ec9SKyle Evans bitcnt_t q_bit_len, p_bit_len;
85*f0865ec9SKyle Evans const ec_priv_key *priv_key;
86*f0865ec9SKyle Evans /* NOTE: hash here is not really a hash ... */
87*f0865ec9SKyle Evans u8 h_buf[LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8))];
88*f0865ec9SKyle Evans prj_pt_src_t G;
89*f0865ec9SKyle Evans prj_pt kG;
90*f0865ec9SKyle Evans nn_src_t q, x;
91*f0865ec9SKyle Evans u8 hsize, r_len, s_len;
92*f0865ec9SKyle Evans int ret, iszero;
93*f0865ec9SKyle Evans nn tmp, s, rx, ke, k, r, e;
94*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
95*f0865ec9SKyle Evans /* b is the blinding mask */
96*f0865ec9SKyle Evans nn b, binv;
97*f0865ec9SKyle Evans b.magic = binv.magic = WORD(0);
98*f0865ec9SKyle Evans #endif /* USE_SIG_BLINDING */
99*f0865ec9SKyle Evans
100*f0865ec9SKyle Evans tmp.magic = s.magic = rx.magic = ke.magic = WORD(0);
101*f0865ec9SKyle Evans k.magic = r.magic = e.magic = WORD(0);
102*f0865ec9SKyle Evans kG.magic = WORD(0);
103*f0865ec9SKyle Evans
104*f0865ec9SKyle Evans /*
105*f0865ec9SKyle Evans * First, verify context has been initialized and private
106*f0865ec9SKyle Evans * part too. This guarantees the context is an EC-RDSA
107*f0865ec9SKyle Evans * signature one and we do not finalize() before init().
108*f0865ec9SKyle Evans */
109*f0865ec9SKyle Evans ret = sig_sign_check_initialized(ctx); EG(ret, err);
110*f0865ec9SKyle Evans ECRDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.ecrdsa), ret, err);
111*f0865ec9SKyle Evans
112*f0865ec9SKyle Evans /* Zero init points */
113*f0865ec9SKyle Evans ret = local_memset(&kG, 0, sizeof(prj_pt)); EG(ret, err);
114*f0865ec9SKyle Evans
115*f0865ec9SKyle Evans /* Make things more readable */
116*f0865ec9SKyle Evans priv_key = &(ctx->key_pair->priv_key);
117*f0865ec9SKyle Evans G = &(priv_key->params->ec_gen);
118*f0865ec9SKyle Evans q = &(priv_key->params->ec_gen_order);
119*f0865ec9SKyle Evans p_bit_len = priv_key->params->ec_fp.p_bitlen;
120*f0865ec9SKyle Evans q_bit_len = priv_key->params->ec_gen_order_bitlen;
121*f0865ec9SKyle Evans x = &(priv_key->x);
122*f0865ec9SKyle Evans r_len = (u8)ECRDSA_R_LEN(q_bit_len);
123*f0865ec9SKyle Evans s_len = (u8)ECRDSA_S_LEN(q_bit_len);
124*f0865ec9SKyle Evans hsize = inputlen;
125*f0865ec9SKyle Evans
126*f0865ec9SKyle Evans MUST_HAVE((NN_MAX_BIT_LEN >= p_bit_len), ret, err);
127*f0865ec9SKyle Evans
128*f0865ec9SKyle Evans MUST_HAVE((siglen == ECRDSA_SIGLEN(q_bit_len)), ret, err);
129*f0865ec9SKyle Evans
130*f0865ec9SKyle Evans dbg_nn_print("p", &(priv_key->params->ec_fp.p));
131*f0865ec9SKyle Evans dbg_nn_print("q", q);
132*f0865ec9SKyle Evans dbg_priv_key_print("x", priv_key);
133*f0865ec9SKyle Evans dbg_pub_key_print("Y", &(ctx->key_pair->pub_key));
134*f0865ec9SKyle Evans dbg_ec_point_print("G", G);
135*f0865ec9SKyle Evans
136*f0865ec9SKyle Evans /*
137*f0865ec9SKyle Evans NOTE: the restart label is removed in CRYPTOFUZZ mode as
138*f0865ec9SKyle Evans we trigger MUST_HAVE instead of restarting in this mode.
139*f0865ec9SKyle Evans restart:
140*f0865ec9SKyle Evans */
141*f0865ec9SKyle Evans /* 2. Get a random value k in ]0, q[ ... */
142*f0865ec9SKyle Evans /* NOTE: copy our input nonce if not NULL */
143*f0865ec9SKyle Evans if(nonce != NULL){
144*f0865ec9SKyle Evans MUST_HAVE((noncelen <= (u8)(BYTECEIL(q_bit_len))), ret, err);
145*f0865ec9SKyle Evans ret = nn_init_from_buf(&k, nonce, noncelen); EG(ret, err);
146*f0865ec9SKyle Evans }
147*f0865ec9SKyle Evans else{
148*f0865ec9SKyle Evans ret = ctx->rand(&k, q); EG(ret, err);
149*f0865ec9SKyle Evans }
150*f0865ec9SKyle Evans
151*f0865ec9SKyle Evans dbg_nn_print("k", &k);
152*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
153*f0865ec9SKyle Evans /* Note: if we use blinding, k and e are multiplied by
154*f0865ec9SKyle Evans * a random value b in ]0,q[ */
155*f0865ec9SKyle Evans ret = nn_get_random_mod(&b, q); EG(ret, err);
156*f0865ec9SKyle Evans dbg_nn_print("b", &b);
157*f0865ec9SKyle Evans #endif /* USE_SIG_BLINDING */
158*f0865ec9SKyle Evans
159*f0865ec9SKyle Evans /* 3. Compute W = kG = (Wx, Wy) */
160*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
161*f0865ec9SKyle Evans /* We use blinding for the scalar multiplication */
162*f0865ec9SKyle Evans ret = prj_pt_mul_blind(&kG, &k, G); EG(ret, err);
163*f0865ec9SKyle Evans #else
164*f0865ec9SKyle Evans ret = prj_pt_mul(&kG, &k, G); EG(ret, err);
165*f0865ec9SKyle Evans #endif /* USE_SIG_BLINDING */
166*f0865ec9SKyle Evans ret = prj_pt_unique(&kG, &kG); EG(ret, err);
167*f0865ec9SKyle Evans dbg_nn_print("W_x", &(kG.X.fp_val));
168*f0865ec9SKyle Evans dbg_nn_print("W_y", &(kG.Y.fp_val));
169*f0865ec9SKyle Evans
170*f0865ec9SKyle Evans /* 4. Compute r = Wx mod q */
171*f0865ec9SKyle Evans ret = nn_mod(&r, &(kG.X.fp_val), q); EG(ret, err);
172*f0865ec9SKyle Evans
173*f0865ec9SKyle Evans /* 5. If r is 0, restart the process at step 2. */
174*f0865ec9SKyle Evans /* NOTE: for the CRYPTOFUZZ mode, we do not restart
175*f0865ec9SKyle Evans * the procedure but throw an assert exception instead.
176*f0865ec9SKyle Evans */
177*f0865ec9SKyle Evans ret = nn_iszero(&r, &iszero); EG(ret, err);
178*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err);
179*f0865ec9SKyle Evans
180*f0865ec9SKyle Evans dbg_nn_print("r", &r);
181*f0865ec9SKyle Evans
182*f0865ec9SKyle Evans /* Export r */
183*f0865ec9SKyle Evans ret = nn_export_to_buf(sig, r_len, &r); EG(ret, err);
184*f0865ec9SKyle Evans
185*f0865ec9SKyle Evans /* 6. Compute e = OS2I(h) mod q. If e is 0, set e to 1. */
186*f0865ec9SKyle Evans /* NOTE: here we have raw ECRDSA, this is the raw input */
187*f0865ec9SKyle Evans MUST_HAVE((input != NULL), ret, err);
188*f0865ec9SKyle Evans /* NOTE: the MUST_HAVE is protected by a preprocessing check
189*f0865ec9SKyle Evans * to avoid -Werror=type-limits errors:
190*f0865ec9SKyle Evans * "error: comparison is always true due to limited range of data type"
191*f0865ec9SKyle Evans */
192*f0865ec9SKyle Evans #if LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8)) < 255
193*f0865ec9SKyle Evans MUST_HAVE(((u32)inputlen <= sizeof(h_buf)), ret, err);
194*f0865ec9SKyle Evans #endif
195*f0865ec9SKyle Evans ret = local_memset(h_buf, 0, sizeof(h_buf)); EG(ret, err);
196*f0865ec9SKyle Evans ret = local_memcpy(h_buf, input, hsize); EG(ret, err);
197*f0865ec9SKyle Evans dbg_buf_print("H(m)", h_buf, hsize);
198*f0865ec9SKyle Evans /* NOTE: this handles a discrepancy between ISO/IEC 14888-3 and
199*f0865ec9SKyle Evans * Russian standard based RFCs.
200*f0865ec9SKyle Evans */
201*f0865ec9SKyle Evans #ifndef USE_ISO14888_3_ECRDSA
202*f0865ec9SKyle Evans ret = _reverse_endianness(h_buf, hsize); EG(ret, err);
203*f0865ec9SKyle Evans #endif
204*f0865ec9SKyle Evans
205*f0865ec9SKyle Evans ret = nn_init_from_buf(&tmp, h_buf, hsize); EG(ret, err);
206*f0865ec9SKyle Evans ret = local_memset(h_buf, 0, hsize); EG(ret, err);
207*f0865ec9SKyle Evans ret = nn_mod(&e, &tmp, q); EG(ret, err);
208*f0865ec9SKyle Evans ret = nn_iszero(&e, &iszero); EG(ret, err);
209*f0865ec9SKyle Evans if (iszero) {
210*f0865ec9SKyle Evans ret = nn_inc(&e, &e); EG(ret, err);
211*f0865ec9SKyle Evans }
212*f0865ec9SKyle Evans dbg_nn_print("e", &e);
213*f0865ec9SKyle Evans
214*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
215*f0865ec9SKyle Evans /* In case of blinding, we blind r and e */
216*f0865ec9SKyle Evans ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err);
217*f0865ec9SKyle Evans ret = nn_mod_mul(&e, &e, &b, q); EG(ret, err);
218*f0865ec9SKyle Evans #endif /* USE_SIG_BLINDING */
219*f0865ec9SKyle Evans
220*f0865ec9SKyle Evans /* Compute s = (rx + ke) mod q */
221*f0865ec9SKyle Evans ret = nn_mod_mul(&rx, &r, x, q); EG(ret, err);
222*f0865ec9SKyle Evans ret = nn_mod_mul(&ke, &k, &e, q); EG(ret, err);
223*f0865ec9SKyle Evans ret = nn_mod_add(&s, &rx, &ke, q); EG(ret, err);
224*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
225*f0865ec9SKyle Evans /* Unblind s */
226*f0865ec9SKyle Evans /* NOTE: we use Fermat's little theorem inversion for
227*f0865ec9SKyle Evans * constant time here. This is possible since q is prime.
228*f0865ec9SKyle Evans */
229*f0865ec9SKyle Evans ret = nn_modinv_fermat(&binv, &b, q); EG(ret, err);
230*f0865ec9SKyle Evans ret = nn_mod_mul(&s, &s, &binv, q); EG(ret, err);
231*f0865ec9SKyle Evans #endif /* USE_SIG_BLINDING */
232*f0865ec9SKyle Evans
233*f0865ec9SKyle Evans /* If s is 0, restart the process at step 2. */
234*f0865ec9SKyle Evans /* 10. If s is 0, restart the process at step 4. */
235*f0865ec9SKyle Evans /* NOTE: for the CRYPTOFUZZ mode, we do not restart
236*f0865ec9SKyle Evans * the procedure but throw an assert exception instead.
237*f0865ec9SKyle Evans */
238*f0865ec9SKyle Evans ret = nn_iszero(&s, &iszero); EG(ret, err);
239*f0865ec9SKyle Evans MUST_HAVE((!iszero), ret, err);
240*f0865ec9SKyle Evans
241*f0865ec9SKyle Evans dbg_nn_print("s", &s);
242*f0865ec9SKyle Evans
243*f0865ec9SKyle Evans /* Return (r,s) */
244*f0865ec9SKyle Evans ret = nn_export_to_buf(sig + r_len, s_len, &s); EG(ret, err);
245*f0865ec9SKyle Evans
246*f0865ec9SKyle Evans err:
247*f0865ec9SKyle Evans nn_uninit(&r);
248*f0865ec9SKyle Evans nn_uninit(&s);
249*f0865ec9SKyle Evans nn_uninit(&tmp);
250*f0865ec9SKyle Evans nn_uninit(&rx);
251*f0865ec9SKyle Evans nn_uninit(&ke);
252*f0865ec9SKyle Evans nn_uninit(&k);
253*f0865ec9SKyle Evans nn_uninit(&e);
254*f0865ec9SKyle Evans prj_pt_uninit(&kG);
255*f0865ec9SKyle Evans
256*f0865ec9SKyle Evans /*
257*f0865ec9SKyle Evans * We can now clear data part of the context. This will clear
258*f0865ec9SKyle Evans * magic and avoid further reuse of the whole context.
259*f0865ec9SKyle Evans */
260*f0865ec9SKyle Evans if(ctx != NULL){
261*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(&(ctx->sign_data.ecrdsa), 0, sizeof(ecrdsa_sign_data)));
262*f0865ec9SKyle Evans }
263*f0865ec9SKyle Evans
264*f0865ec9SKyle Evans /* Clean what remains on the stack */
265*f0865ec9SKyle Evans VAR_ZEROIFY(r_len);
266*f0865ec9SKyle Evans VAR_ZEROIFY(s_len);
267*f0865ec9SKyle Evans VAR_ZEROIFY(q_bit_len);
268*f0865ec9SKyle Evans VAR_ZEROIFY(p_bit_len);
269*f0865ec9SKyle Evans VAR_ZEROIFY(hsize);
270*f0865ec9SKyle Evans PTR_NULLIFY(priv_key);
271*f0865ec9SKyle Evans PTR_NULLIFY(G);
272*f0865ec9SKyle Evans PTR_NULLIFY(q);
273*f0865ec9SKyle Evans PTR_NULLIFY(x);
274*f0865ec9SKyle Evans
275*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
276*f0865ec9SKyle Evans nn_uninit(&b);
277*f0865ec9SKyle Evans nn_uninit(&binv);
278*f0865ec9SKyle Evans #endif /* USE_SIG_BLINDING */
279*f0865ec9SKyle Evans
280*f0865ec9SKyle Evans return ret;
281*f0865ec9SKyle Evans }
282*f0865ec9SKyle Evans
283*f0865ec9SKyle Evans /******************************/
284*f0865ec9SKyle Evans #define ECRDSA_VERIFY_MAGIC ((word_t)(0xa8e16b7e8180cb9aULL))
285*f0865ec9SKyle Evans #define ECRDSA_VERIFY_CHECK_INITIALIZED(A, ret, err) \
286*f0865ec9SKyle Evans MUST_HAVE((((const void *)(A)) != NULL) && \
287*f0865ec9SKyle Evans ((A)->magic == ECRDSA_VERIFY_MAGIC), ret, err)
288*f0865ec9SKyle Evans
ecrdsa_verify_raw(struct ec_verify_context * ctx,const u8 * input,u8 inputlen)289*f0865ec9SKyle Evans int ecrdsa_verify_raw(struct ec_verify_context *ctx, const u8 *input, u8 inputlen)
290*f0865ec9SKyle Evans {
291*f0865ec9SKyle Evans prj_pt_src_t G, Y;
292*f0865ec9SKyle Evans nn_src_t q;
293*f0865ec9SKyle Evans nn tmp, h, r_prime, e, v, u;
294*f0865ec9SKyle Evans prj_pt vY, uG;
295*f0865ec9SKyle Evans prj_pt_t Wprime;
296*f0865ec9SKyle Evans /* NOTE: hash here is not really a hash ... */
297*f0865ec9SKyle Evans u8 h_buf[LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8))];
298*f0865ec9SKyle Evans nn *r, *s;
299*f0865ec9SKyle Evans u8 hsize;
300*f0865ec9SKyle Evans int ret, iszero, cmp;
301*f0865ec9SKyle Evans
302*f0865ec9SKyle Evans tmp.magic = h.magic = r_prime.magic = e.magic = WORD(0);
303*f0865ec9SKyle Evans v.magic = u.magic = WORD(0);
304*f0865ec9SKyle Evans vY.magic = uG.magic = WORD(0);
305*f0865ec9SKyle Evans
306*f0865ec9SKyle Evans /* NOTE: we reuse uG for Wprime to optimize local variables */
307*f0865ec9SKyle Evans Wprime = &uG;
308*f0865ec9SKyle Evans
309*f0865ec9SKyle Evans /*
310*f0865ec9SKyle Evans * First, verify context has been initialized and public
311*f0865ec9SKyle Evans * part too. This guarantees the context is an EC-RDSA
312*f0865ec9SKyle Evans * verification one and we do not finalize() before init().
313*f0865ec9SKyle Evans */
314*f0865ec9SKyle Evans ret = sig_verify_check_initialized(ctx); EG(ret, err);
315*f0865ec9SKyle Evans ECRDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.ecrdsa), ret, err);
316*f0865ec9SKyle Evans
317*f0865ec9SKyle Evans /* Zero init points */
318*f0865ec9SKyle Evans ret = local_memset(&uG, 0, sizeof(prj_pt)); EG(ret, err);
319*f0865ec9SKyle Evans ret = local_memset(&vY, 0, sizeof(prj_pt)); EG(ret, err);
320*f0865ec9SKyle Evans
321*f0865ec9SKyle Evans /* Make things more readable */
322*f0865ec9SKyle Evans G = &(ctx->pub_key->params->ec_gen);
323*f0865ec9SKyle Evans Y = &(ctx->pub_key->y);
324*f0865ec9SKyle Evans q = &(ctx->pub_key->params->ec_gen_order);
325*f0865ec9SKyle Evans r = &(ctx->verify_data.ecrdsa.r);
326*f0865ec9SKyle Evans s = &(ctx->verify_data.ecrdsa.s);
327*f0865ec9SKyle Evans hsize = inputlen;
328*f0865ec9SKyle Evans
329*f0865ec9SKyle Evans /* 2. Compute h = H(m) */
330*f0865ec9SKyle Evans /* NOTE: here we have raw ECRDSA, this is the raw input */
331*f0865ec9SKyle Evans MUST_HAVE((input != NULL), ret, err);
332*f0865ec9SKyle Evans /* NOTE: the MUST_HAVE is protected by a preprocessing check
333*f0865ec9SKyle Evans * to avoid -Werror=type-limits errors:
334*f0865ec9SKyle Evans * "error: comparison is always true due to limited range of data type"
335*f0865ec9SKyle Evans */
336*f0865ec9SKyle Evans #if LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8)) < 255
337*f0865ec9SKyle Evans MUST_HAVE(((u32)inputlen <= sizeof(h_buf)), ret, err);
338*f0865ec9SKyle Evans #endif
339*f0865ec9SKyle Evans
340*f0865ec9SKyle Evans ret = local_memset(h_buf, 0, sizeof(h_buf)); EG(ret, err);
341*f0865ec9SKyle Evans ret = local_memcpy(h_buf, input, hsize); EG(ret, err);
342*f0865ec9SKyle Evans dbg_buf_print("H(m)", h_buf, hsize);
343*f0865ec9SKyle Evans /* NOTE: this handles a discrepancy between ISO/IEC 14888-3 and
344*f0865ec9SKyle Evans * Russian standard based RFCs.
345*f0865ec9SKyle Evans */
346*f0865ec9SKyle Evans #ifndef USE_ISO14888_3_ECRDSA
347*f0865ec9SKyle Evans ret = _reverse_endianness(h_buf, hsize); EG(ret, err);
348*f0865ec9SKyle Evans #endif
349*f0865ec9SKyle Evans
350*f0865ec9SKyle Evans /* 3. Compute e = OS2I(h)^-1 mod q */
351*f0865ec9SKyle Evans ret = nn_init_from_buf(&tmp, h_buf, hsize); EG(ret, err);
352*f0865ec9SKyle Evans ret = local_memset(h_buf, 0, hsize); EG(ret, err);
353*f0865ec9SKyle Evans ret = nn_mod(&h, &tmp, q); EG(ret, err); /* h = OS2I(h) mod q */
354*f0865ec9SKyle Evans ret = nn_iszero(&h, &iszero); EG(ret, err);
355*f0865ec9SKyle Evans if (iszero) { /* If h is equal to 0, set it to 1 */
356*f0865ec9SKyle Evans ret = nn_inc(&h, &h); EG(ret, err);
357*f0865ec9SKyle Evans }
358*f0865ec9SKyle Evans ret = nn_modinv(&e, &h, q); EG(ret, err); /* e = h^-1 mod q */
359*f0865ec9SKyle Evans
360*f0865ec9SKyle Evans /* 4. Compute u = es mod q */
361*f0865ec9SKyle Evans ret = nn_mul(&tmp, &e, s); EG(ret, err);
362*f0865ec9SKyle Evans ret = nn_mod(&u, &tmp, q); EG(ret, err);
363*f0865ec9SKyle Evans
364*f0865ec9SKyle Evans /* 5. Compute v = -er mod q
365*f0865ec9SKyle Evans *
366*f0865ec9SKyle Evans * Because we only support positive integers, we compute
367*f0865ec9SKyle Evans * v = -er mod q = q - (er mod q) (except when er is 0).
368*f0865ec9SKyle Evans */
369*f0865ec9SKyle Evans ret = nn_mul(&tmp, &e, r); EG(ret, err); /* tmp = er */
370*f0865ec9SKyle Evans ret = nn_mod(&tmp, &tmp, q); EG(ret, err); /* tmp = er mod q */
371*f0865ec9SKyle Evans ret = nn_mod_neg(&v, &tmp, q); EG(ret, err); /* negate tmp */
372*f0865ec9SKyle Evans
373*f0865ec9SKyle Evans /* 6. Compute W' = uG + vY = (W'_x, W'_y) */
374*f0865ec9SKyle Evans ret = prj_pt_mul(&uG, &u, G); EG(ret, err);
375*f0865ec9SKyle Evans ret = prj_pt_mul(&vY, &v, Y); EG(ret, err);
376*f0865ec9SKyle Evans ret = prj_pt_add(Wprime, &uG, &vY); EG(ret, err);
377*f0865ec9SKyle Evans ret = prj_pt_unique(Wprime, Wprime); EG(ret, err);
378*f0865ec9SKyle Evans dbg_nn_print("W'_x", &(Wprime->X.fp_val));
379*f0865ec9SKyle Evans dbg_nn_print("W'_y", &(Wprime->Y.fp_val));
380*f0865ec9SKyle Evans
381*f0865ec9SKyle Evans /* 7. Compute r' = W'_x mod q */
382*f0865ec9SKyle Evans ret = nn_mod(&r_prime, &(Wprime->X.fp_val), q); EG(ret, err);
383*f0865ec9SKyle Evans
384*f0865ec9SKyle Evans /* 8. Check r and r' are the same */
385*f0865ec9SKyle Evans ret = nn_cmp(r, &r_prime, &cmp); EG(ret, err);
386*f0865ec9SKyle Evans ret = (cmp == 0) ? 0 : -1;
387*f0865ec9SKyle Evans
388*f0865ec9SKyle Evans err:
389*f0865ec9SKyle Evans nn_uninit(&r_prime);
390*f0865ec9SKyle Evans nn_uninit(&tmp);
391*f0865ec9SKyle Evans nn_uninit(&h);
392*f0865ec9SKyle Evans nn_uninit(&e);
393*f0865ec9SKyle Evans nn_uninit(&u);
394*f0865ec9SKyle Evans nn_uninit(&v);
395*f0865ec9SKyle Evans prj_pt_uninit(&vY);
396*f0865ec9SKyle Evans prj_pt_uninit(&uG);
397*f0865ec9SKyle Evans
398*f0865ec9SKyle Evans /*
399*f0865ec9SKyle Evans * We can now clear data part of the context. This will clear
400*f0865ec9SKyle Evans * magic and avoid further reuse of the whole context.
401*f0865ec9SKyle Evans */
402*f0865ec9SKyle Evans if(ctx != NULL){
403*f0865ec9SKyle Evans IGNORE_RET_VAL(local_memset(&(ctx->verify_data.ecrdsa), 0,
404*f0865ec9SKyle Evans sizeof(ecrdsa_verify_data)));
405*f0865ec9SKyle Evans }
406*f0865ec9SKyle Evans
407*f0865ec9SKyle Evans /* Clean what remains on the stack */
408*f0865ec9SKyle Evans PTR_NULLIFY(Wprime);
409*f0865ec9SKyle Evans PTR_NULLIFY(G);
410*f0865ec9SKyle Evans PTR_NULLIFY(Y);
411*f0865ec9SKyle Evans PTR_NULLIFY(q);
412*f0865ec9SKyle Evans PTR_NULLIFY(r);
413*f0865ec9SKyle Evans PTR_NULLIFY(s);
414*f0865ec9SKyle Evans VAR_ZEROIFY(hsize);
415*f0865ec9SKyle Evans
416*f0865ec9SKyle Evans return ret;
417*f0865ec9SKyle Evans }
418*f0865ec9SKyle Evans
419*f0865ec9SKyle Evans #else /* WITH_SIG_ECRDSA && USE_CRYPTOFUZZ */
420*f0865ec9SKyle Evans
421*f0865ec9SKyle Evans /*
422*f0865ec9SKyle Evans * Dummy definition to avoid the empty translation unit ISO C warning
423*f0865ec9SKyle Evans */
424*f0865ec9SKyle Evans typedef int dummy;
425*f0865ec9SKyle Evans #endif /* WITH_SIG_ECRDSA */
426