1 /* 2 * Copyright (C) 2017 - This file is part of libecc project 3 * 4 * Authors: 5 * Ryad BENADJILA <ryadbenadjila@gmail.com> 6 * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7 * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8 * 9 * Contributors: 10 * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11 * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12 * 13 * This software is licensed under a dual BSD and GPL v2 license. 14 * See LICENSE file at the root folder of the project. 15 */ 16 #include <libecc/lib_ecc_config.h> 17 #ifdef WITH_SIG_ECRDSA 18 19 #include <libecc/nn/nn_rand.h> 20 #include <libecc/nn/nn_mul_public.h> 21 #include <libecc/nn/nn_logical.h> 22 23 #include <libecc/sig/sig_algs_internal.h> 24 #include <libecc/sig/ec_key.h> 25 #ifdef VERBOSE_INNER_VALUES 26 #define EC_SIG_ALG "ECRDSA" 27 #endif 28 #include <libecc/utils/dbg_sig.h> 29 30 31 /* 32 * NOTE: ISO/IEC 14888-3 standard seems to diverge from the existing implementations 33 * of ECRDSA when treating the message hash, and from the examples of certificates provided 34 * in RFC 7091 and draft-deremin-rfc4491-bis. While in ISO/IEC 14888-3 it is explicitely asked 35 * to proceed with the hash of the message as big endian, the RFCs derived from the Russian 36 * standard expect the hash value to be treated as little endian when importing it as an integer 37 * (this discrepancy is exhibited and confirmed by test vectors present in ISO/IEC 14888-3, and 38 * by X.509 certificates present in the RFCs). This seems (to be confirmed) to be a discrepancy of 39 * ISO/IEC 14888-3 algorithm description that must be fixed there. 40 * 41 * In order to be conservative, libecc uses the Russian standard behavior as expected to be in line with 42 * other implemetations, but keeps the ISO/IEC 14888-3 behavior if forced/asked by the user using 43 * the USE_ISO14888_3_ECRDSA toggle. This allows to keep backward compatibility with previous versions of the 44 * library if needed. 45 * 46 */ 47 #ifndef USE_ISO14888_3_ECRDSA 48 /* Reverses the endiannes of a buffer in place */ 49 ATTRIBUTE_WARN_UNUSED_RET static inline int _reverse_endianness(u8 *buf, u16 buf_size) 50 { 51 u16 i; 52 u8 tmp; 53 int ret; 54 55 MUST_HAVE((buf != NULL), ret, err); 56 57 if(buf_size > 1){ 58 for(i = 0; i < (buf_size / 2); i++){ 59 tmp = buf[i]; 60 buf[i] = buf[buf_size - 1 - i]; 61 buf[buf_size - 1 - i] = tmp; 62 } 63 } 64 65 ret = 0; 66 err: 67 return ret; 68 } 69 #endif 70 71 int ecrdsa_init_pub_key(ec_pub_key *out_pub, const ec_priv_key *in_priv) 72 { 73 int ret, cmp; 74 prj_pt_src_t G; 75 nn_src_t q; 76 77 MUST_HAVE((out_pub != NULL), ret, err); 78 79 /* Zero init public key to be generated */ 80 ret = local_memset(out_pub, 0, sizeof(ec_pub_key)); EG(ret, err); 81 82 ret = priv_key_check_initialized_and_type(in_priv, ECRDSA); EG(ret, err); 83 q = &(in_priv->params->ec_gen_order); 84 85 /* Sanity check on key */ 86 MUST_HAVE((!nn_cmp(&(in_priv->x), q, &cmp)) && (cmp < 0), ret, err); 87 88 /* Y = xG */ 89 G = &(in_priv->params->ec_gen); 90 /* Use blinding when computing point scalar multiplication */ 91 ret = prj_pt_mul_blind(&(out_pub->y), &(in_priv->x), G); EG(ret, err); 92 93 out_pub->key_type = ECRDSA; 94 out_pub->params = in_priv->params; 95 out_pub->magic = PUB_KEY_MAGIC; 96 97 err: 98 return ret; 99 } 100 101 int ecrdsa_siglen(u16 p_bit_len, u16 q_bit_len, u8 hsize, u8 blocksize, u8 *siglen) 102 { 103 int ret; 104 105 MUST_HAVE((siglen != NULL), ret, err); 106 MUST_HAVE((p_bit_len <= CURVES_MAX_P_BIT_LEN) && 107 (q_bit_len <= CURVES_MAX_Q_BIT_LEN) && 108 (hsize <= MAX_DIGEST_SIZE) && (blocksize <= MAX_BLOCK_SIZE), ret, err); 109 (*siglen) = (u8)ECRDSA_SIGLEN(q_bit_len); 110 ret = 0; 111 112 err: 113 return ret; 114 } 115 116 /* 117 * Generic *internal* EC-RDSA signature functions (init, update and finalize). 118 * Their purpose is to allow passing a specific hash function (along with 119 * its output size) and the random ephemeral key k, so that compliance 120 * tests against test vectors can be made without ugly hack in the code 121 * itself. 122 * 123 * Global EC-RDSA signature process is as follows (I,U,F provides 124 * information in which function(s) (init(), update() or finalize()) 125 * a specific step is performed): 126 * 127 *| IUF - EC-RDSA signature 128 *| 129 *| UF 1. Compute h = H(m) 130 *| F 2. Get a random value k in ]0,q[ 131 *| F 3. Compute W = (W_x,W_y) = kG 132 *| F 4. Compute r = W_x mod q 133 *| F 5. If r is 0, restart the process at step 2. 134 *| F 6. Compute e = OS2I(h) mod q. If e is 0, set e to 1. 135 *| NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated. 136 *| e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h 137 *| is reversed for RFCs. 138 *| F 7. Compute s = (rx + ke) mod q 139 *| F 8. If s is 0, restart the process at step 2. 140 *| F 11. Return (r,s) 141 * 142 */ 143 144 #define ECRDSA_SIGN_MAGIC ((word_t)(0xcc97bbc8ada8973cULL)) 145 #define ECRDSA_SIGN_CHECK_INITIALIZED(A, ret, err) \ 146 MUST_HAVE((((void *)(A)) != NULL) && \ 147 ((A)->magic == ECRDSA_SIGN_MAGIC), ret, err) 148 149 int _ecrdsa_sign_init(struct ec_sign_context *ctx) 150 { 151 int ret; 152 153 /* First, verify context has been initialized */ 154 ret = sig_sign_check_initialized(ctx); EG(ret, err); 155 156 /* Additional sanity checks on input params from context */ 157 ret = key_pair_check_initialized_and_type(ctx->key_pair, ECRDSA); EG(ret, err); 158 MUST_HAVE((ctx->h != NULL) && (ctx->h->digest_size <= MAX_DIGEST_SIZE) && 159 (ctx->h->block_size <= MAX_BLOCK_SIZE), ret, err); 160 161 /* 162 * Initialize hash context stored in our private part of context 163 * and record data init has been done 164 */ 165 /* Since we call a callback, sanity check our mapping */ 166 ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err); 167 ret = ctx->h->hfunc_init(&(ctx->sign_data.ecrdsa.h_ctx)); EG(ret, err); 168 169 ctx->sign_data.ecrdsa.magic = ECRDSA_SIGN_MAGIC; 170 171 err: 172 return ret; 173 } 174 175 int _ecrdsa_sign_update(struct ec_sign_context *ctx, 176 const u8 *chunk, u32 chunklen) 177 { 178 int ret; 179 /* 180 * First, verify context has been initialized and private 181 * part too. This guarantees the context is an EC-RDSA 182 * signature one and we do not update() or finalize() 183 * before init(). 184 */ 185 ret = sig_sign_check_initialized(ctx); EG(ret, err); 186 ECRDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.ecrdsa), ret, err); 187 188 /* Since we call a callback, sanity check our mapping */ 189 ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err); 190 ret = ctx->h->hfunc_update(&(ctx->sign_data.ecrdsa.h_ctx), chunk, chunklen); 191 192 err: 193 return ret; 194 } 195 196 int _ecrdsa_sign_finalize(struct ec_sign_context *ctx, u8 *sig, u8 siglen) 197 { 198 bitcnt_t q_bit_len, p_bit_len; 199 const ec_priv_key *priv_key; 200 u8 h_buf[MAX_DIGEST_SIZE]; 201 prj_pt_src_t G; 202 prj_pt kG; 203 nn_src_t q, x; 204 u8 hsize, r_len, s_len; 205 int ret, iszero, cmp; 206 nn s, rx, ke, k, r, e; 207 #ifdef USE_SIG_BLINDING 208 /* b is the blinding mask */ 209 nn b, binv; 210 b.magic = binv.magic = WORD(0); 211 #endif /* USE_SIG_BLINDING */ 212 213 kG.magic = WORD(0); 214 s.magic = rx.magic = ke.magic = WORD(0); 215 k.magic = r.magic = e.magic = WORD(0); 216 217 /* 218 * First, verify context has been initialized and private 219 * part too. This guarantees the context is an EC-RDSA 220 * signature one and we do not finalize() before init(). 221 */ 222 ret = sig_sign_check_initialized(ctx); EG(ret, err); 223 ECRDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.ecrdsa), ret, err); 224 225 /* Zero init points */ 226 ret = local_memset(&kG, 0, sizeof(prj_pt)); EG(ret, err); 227 228 /* Make things more readable */ 229 priv_key = &(ctx->key_pair->priv_key); 230 G = &(priv_key->params->ec_gen); 231 q = &(priv_key->params->ec_gen_order); 232 p_bit_len = priv_key->params->ec_fp.p_bitlen; 233 q_bit_len = priv_key->params->ec_gen_order_bitlen; 234 x = &(priv_key->x); 235 r_len = (u8)ECRDSA_R_LEN(q_bit_len); 236 s_len = (u8)ECRDSA_S_LEN(q_bit_len); 237 hsize = ctx->h->digest_size; 238 239 /* Sanity check */ 240 ret = nn_cmp(x, q, &cmp); EG(ret, err); 241 /* This should not happen and means that our 242 * private key is not compliant! 243 */ 244 MUST_HAVE((cmp < 0) && (p_bit_len <= NN_MAX_BIT_LEN) && (siglen == ECRDSA_SIGLEN(q_bit_len)), ret, err); 245 246 dbg_nn_print("p", &(priv_key->params->ec_fp.p)); 247 dbg_nn_print("q", q); 248 dbg_priv_key_print("x", priv_key); 249 dbg_pub_key_print("Y", &(ctx->key_pair->pub_key)); 250 dbg_ec_point_print("G", G); 251 252 restart: 253 /* 2. Get a random value k in ]0, q[ ... */ 254 #ifdef NO_KNOWN_VECTORS 255 /* NOTE: when we do not need self tests for known vectors, 256 * we can be strict about random function handler! 257 * This allows us to avoid the corruption of such a pointer. 258 */ 259 /* Sanity check on the handler before calling it */ 260 MUST_HAVE((ctx->rand == nn_get_random_mod), ret, err); 261 #endif 262 MUST_HAVE((ctx->rand != NULL), ret, err); 263 ret = ctx->rand(&k, q); EG(ret, err); 264 265 dbg_nn_print("k", &k); 266 #ifdef USE_SIG_BLINDING 267 /* Note: if we use blinding, k and e are multiplied by 268 * a random value b in ]0,q[ */ 269 ret = nn_get_random_mod(&b, q); EG(ret, err); 270 dbg_nn_print("b", &b); 271 #endif /* USE_SIG_BLINDING */ 272 273 /* 3. Compute W = kG = (Wx, Wy) */ 274 #ifdef USE_SIG_BLINDING 275 /* We use blinding for the scalar multiplication */ 276 ret = prj_pt_mul_blind(&kG, &k, G); EG(ret, err); 277 #else 278 ret = prj_pt_mul(&kG, &k, G); EG(ret, err); 279 #endif /* USE_SIG_BLINDING */ 280 ret = prj_pt_unique(&kG, &kG); EG(ret, err); 281 dbg_nn_print("W_x", &(kG.X.fp_val)); 282 dbg_nn_print("W_y", &(kG.Y.fp_val)); 283 284 /* 4. Compute r = Wx mod q */ 285 ret = nn_mod(&r, &(kG.X.fp_val), q); EG(ret, err); 286 287 /* 5. If r is 0, restart the process at step 2. */ 288 ret = nn_iszero(&r, &iszero); EG(ret, err); 289 if (iszero) { 290 goto restart; 291 } 292 dbg_nn_print("r", &r); 293 294 /* Export r */ 295 ret = nn_export_to_buf(sig, r_len, &r); EG(ret, err); 296 297 /* 6. Compute e = OS2I(h) mod q. If e is 0, set e to 1. */ 298 ret = local_memset(h_buf, 0, hsize); EG(ret, err); 299 /* Since we call a callback, sanity check our mapping */ 300 ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err); 301 ret = ctx->h->hfunc_finalize(&(ctx->sign_data.ecrdsa.h_ctx), h_buf); EG(ret, err); 302 dbg_buf_print("H(m)", h_buf, hsize); 303 /* NOTE: this handles a discrepancy between ISO/IEC 14888-3 and 304 * Russian standard based RFCs. 305 */ 306 #ifndef USE_ISO14888_3_ECRDSA 307 ret = _reverse_endianness(h_buf, hsize); EG(ret, err); 308 #endif 309 ret = nn_init_from_buf(&e, h_buf, hsize); EG(ret, err); 310 ret = local_memset(h_buf, 0, hsize); EG(ret, err); 311 ret = nn_mod(&e, &e, q); EG(ret, err); 312 ret = nn_iszero(&e, &iszero); EG(ret, err); 313 if (iszero) { 314 ret = nn_inc(&e, &e); EG(ret, err); 315 } 316 dbg_nn_print("e", &e); 317 318 #ifdef USE_SIG_BLINDING 319 /* In case of blinding, we blind r and e */ 320 ret = nn_mod_mul(&r, &r, &b, q); EG(ret, err); 321 ret = nn_mod_mul(&e, &e, &b, q); EG(ret, err); 322 #endif /* USE_SIG_BLINDING */ 323 324 /* Compute s = (rx + ke) mod q */ 325 ret = nn_mod_mul(&rx, &r, x, q); EG(ret, err); 326 ret = nn_mod_mul(&ke, &k, &e, q); EG(ret, err); 327 ret = nn_mod_add(&s, &rx, &ke, q); EG(ret, err); 328 #ifdef USE_SIG_BLINDING 329 /* Unblind s */ 330 /* NOTE: we use Fermat's little theorem inversion for 331 * constant time here. This is possible since q is prime. 332 */ 333 ret = nn_modinv_fermat(&binv, &b, q); EG(ret, err); 334 ret = nn_mod_mul(&s, &s, &binv, q); EG(ret, err); 335 #endif /* USE_SIG_BLINDING */ 336 337 /* If s is 0, restart the process at step 2. */ 338 ret = nn_iszero(&s, &iszero); EG(ret, err); 339 if (iszero) { 340 goto restart; 341 } 342 343 dbg_nn_print("s", &s); 344 345 /* Return (r,s) */ 346 ret = nn_export_to_buf(sig + r_len, s_len, &s); 347 348 err: 349 prj_pt_uninit(&kG); 350 nn_uninit(&r); 351 nn_uninit(&s); 352 nn_uninit(&s); 353 nn_uninit(&rx); 354 nn_uninit(&ke); 355 nn_uninit(&k); 356 nn_uninit(&r); 357 nn_uninit(&e); 358 #ifdef USE_SIG_BLINDING 359 nn_uninit(&b); 360 nn_uninit(&binv); 361 #endif 362 363 /* 364 * We can now clear data part of the context. This will clear 365 * magic and avoid further reuse of the whole context. 366 */ 367 if(ctx != NULL){ 368 IGNORE_RET_VAL(local_memset(&(ctx->sign_data.ecrdsa), 0, sizeof(ecrdsa_sign_data))); 369 } 370 371 /* Clean what remains on the stack */ 372 VAR_ZEROIFY(r_len); 373 VAR_ZEROIFY(s_len); 374 VAR_ZEROIFY(q_bit_len); 375 VAR_ZEROIFY(p_bit_len); 376 VAR_ZEROIFY(hsize); 377 PTR_NULLIFY(priv_key); 378 PTR_NULLIFY(G); 379 PTR_NULLIFY(q); 380 PTR_NULLIFY(x); 381 382 return ret; 383 } 384 385 #define ECRDSA_VERIFY_MAGIC ((word_t)(0xa8e16b7e8180cb9aULL)) 386 #define ECRDSA_VERIFY_CHECK_INITIALIZED(A, ret, err) \ 387 MUST_HAVE((((void *)(A)) != NULL) && \ 388 ((A)->magic == ECRDSA_VERIFY_MAGIC), ret, err) 389 390 /* 391 * Generic *internal* EC-RDSA verification functions (init, update and finalize). 392 * Their purpose is to allow passing a specific hash function (along with 393 * their output size) and the random ephemeral key k, so that compliance 394 * tests against test vectors can be made without ugly hack in the code 395 * itself. 396 * 397 * Global EC-RDSA verification process is as follows (I,U,F provides 398 * information in which function(s) (init(), update() or finalize()) 399 * a specific step is performed): 400 * 401 *| IUF - EC-RDSA verification 402 *| 403 *| UF 1. Check that r and s are both in ]0,q[ 404 *| F 2. Compute h = H(m) 405 *| F 3. Compute e = OS2I(h)^-1 mod q 406 *| NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated. 407 *| e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h 408 *| is reversed for RFCs. 409 *| F 4. Compute u = es mod q 410 *| F 5. Compute v = -er mod q 411 *| F 6. Compute W' = uG + vY = (W'_x, W'_y) 412 *| F 7. Compute r' = W'_x mod q 413 *| F 8. Check r and r' are the same 414 * 415 */ 416 417 int _ecrdsa_verify_init(struct ec_verify_context *ctx, 418 const u8 *sig, u8 siglen) 419 { 420 bitcnt_t q_bit_len; 421 u8 r_len, s_len; 422 nn_src_t q; 423 nn s, r; 424 int ret, iszero1, iszero2, cmp1, cmp2; 425 s.magic = r.magic = WORD(0); 426 427 /* First, verify context has been initialized */ 428 ret = sig_verify_check_initialized(ctx); EG(ret, err); 429 430 /* Do some sanity checks on input params */ 431 ret = pub_key_check_initialized_and_type(ctx->pub_key, ECRDSA); EG(ret, err); 432 MUST_HAVE((ctx->h != NULL) && (ctx->h->digest_size <= MAX_DIGEST_SIZE) && 433 (ctx->h->block_size <= MAX_BLOCK_SIZE), ret, err); 434 435 /* Make things more readable */ 436 q = &(ctx->pub_key->params->ec_gen_order); 437 q_bit_len = ctx->pub_key->params->ec_gen_order_bitlen; 438 r_len = (u8)ECRDSA_R_LEN(q_bit_len); 439 s_len = (u8)ECRDSA_S_LEN(q_bit_len); 440 441 MUST_HAVE(siglen == ECRDSA_SIGLEN(q_bit_len), ret, err); 442 443 /* 1. Check that r and s are both in ]0,q[ */ 444 ret = nn_init_from_buf(&r, sig, r_len); EG(ret, err); 445 ret = nn_init_from_buf(&s, sig + r_len, s_len); EG(ret, err); 446 ret = nn_iszero(&s, &iszero1); EG(ret, err); 447 ret = nn_iszero(&r, &iszero2); EG(ret, err); 448 ret = nn_cmp(&s, q, &cmp1); EG(ret, err); 449 ret = nn_cmp(&s, q, &cmp2); EG(ret, err); 450 MUST_HAVE((!iszero1) && (cmp1 < 0) && (!iszero2) && (cmp2 < 0), ret, err); 451 452 /* Initialize the remaining of verify context. */ 453 ret = nn_copy(&(ctx->verify_data.ecrdsa.r), &r); EG(ret, err); 454 ret = nn_copy(&(ctx->verify_data.ecrdsa.s), &s); EG(ret, err); 455 /* Since we call a callback, sanity check our mapping */ 456 ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err); 457 ret = ctx->h->hfunc_init(&(ctx->verify_data.ecrdsa.h_ctx)); EG(ret, err); 458 459 ctx->verify_data.ecrdsa.magic = ECRDSA_VERIFY_MAGIC; 460 461 err: 462 nn_uninit(&s); 463 nn_uninit(&r); 464 465 /* Clean what remains on the stack */ 466 VAR_ZEROIFY(q_bit_len); 467 VAR_ZEROIFY(r_len); 468 VAR_ZEROIFY(s_len); 469 PTR_NULLIFY(q); 470 471 return ret; 472 } 473 474 int _ecrdsa_verify_update(struct ec_verify_context *ctx, 475 const u8 *chunk, u32 chunklen) 476 { 477 int ret; 478 479 /* 480 * First, verify context has been initialized and public 481 * part too. This guarantees the context is an EC-RDSA 482 * verification one and we do not update() or finalize() 483 * before init(). 484 */ 485 ret = sig_verify_check_initialized(ctx); EG(ret, err); 486 ECRDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.ecrdsa), ret, err); 487 488 /* 2. Compute h = H(m) */ 489 /* Since we call a callback, sanity check our mapping */ 490 ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err); 491 ret = ctx->h->hfunc_update(&(ctx->verify_data.ecrdsa.h_ctx), chunk, 492 chunklen); 493 494 err: 495 return ret; 496 } 497 498 int _ecrdsa_verify_finalize(struct ec_verify_context *ctx) 499 { 500 prj_pt_src_t G, Y; 501 nn_src_t q; 502 nn h, r_prime, e, v, u; 503 prj_pt vY, uG; 504 prj_pt_t Wprime; 505 u8 h_buf[MAX_DIGEST_SIZE]; 506 nn *r, *s; 507 u8 hsize; 508 int ret, iszero, cmp; 509 510 h.magic = r_prime.magic = e.magic = v.magic = u.magic = WORD(0); 511 vY.magic = uG.magic = WORD(0); 512 513 /* NOTE: we reuse uG for Wprime to optimize local variables */ 514 Wprime = &uG; 515 516 /* 517 * First, verify context has been initialized and public 518 * part too. This guarantees the context is an EC-RDSA 519 * verification one and we do not finalize() before init(). 520 */ 521 ret = sig_verify_check_initialized(ctx); EG(ret, err); 522 ECRDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.ecrdsa), ret, err); 523 524 /* Zero init points */ 525 ret = local_memset(&uG, 0, sizeof(prj_pt)); EG(ret, err); 526 ret = local_memset(&vY, 0, sizeof(prj_pt)); EG(ret, err); 527 528 /* Make things more readable */ 529 G = &(ctx->pub_key->params->ec_gen); 530 Y = &(ctx->pub_key->y); 531 q = &(ctx->pub_key->params->ec_gen_order); 532 r = &(ctx->verify_data.ecrdsa.r); 533 s = &(ctx->verify_data.ecrdsa.s); 534 hsize = ctx->h->digest_size; 535 536 /* 2. Compute h = H(m) */ 537 ret = local_memset(h_buf, 0, hsize); EG(ret, err); 538 /* Since we call a callback, sanity check our mapping */ 539 ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err); 540 ret = ctx->h->hfunc_finalize(&(ctx->verify_data.ecrdsa.h_ctx), h_buf); EG(ret, err); 541 dbg_buf_print("H(m)", h_buf, hsize); 542 /* NOTE: this handles a discrepancy between ISO/IEC 14888-3 and 543 * Russian standard based RFCs. 544 */ 545 #ifndef USE_ISO14888_3_ECRDSA 546 ret = _reverse_endianness(h_buf, hsize); EG(ret, err); 547 #endif 548 549 /* 3. Compute e = OS2I(h)^-1 mod q */ 550 ret = nn_init_from_buf(&h, h_buf, hsize); EG(ret, err); 551 ret = local_memset(h_buf, 0, hsize); EG(ret, err); 552 ret = nn_mod(&h, &h, q); EG(ret, err); /* h = OS2I(h) mod q */ 553 ret = nn_iszero(&h, &iszero); EG(ret, err); 554 if (iszero) { /* If h is equal to 0, set it to 1 */ 555 ret = nn_inc(&h, &h); EG(ret, err); 556 } 557 ret = nn_modinv(&e, &h, q); EG(ret, err); /* e = h^-1 mod q */ 558 559 /* 4. Compute u = es mod q */ 560 ret = nn_mod_mul(&u, &e, s, q); EG(ret, err); 561 562 /* 5. Compute v = -er mod q 563 * 564 * Because we only support positive integers, we compute 565 * v = -er mod q = q - (er mod q) (except when er is 0). 566 * NOTE: we reuse e for er computation to avoid losing 567 * a variable. 568 */ 569 ret = nn_mod_mul(&e, &e, r, q); EG(ret, err); 570 ret = nn_mod_neg(&v, &e, q); EG(ret, err); 571 572 /* 6. Compute W' = uG + vY = (W'_x, W'_y) */ 573 ret = prj_pt_mul(&uG, &u, G); EG(ret, err); 574 ret = prj_pt_mul(&vY, &v, Y); EG(ret, err); 575 ret = prj_pt_add(Wprime, &uG, &vY); EG(ret, err); 576 ret = prj_pt_unique(Wprime, Wprime); EG(ret, err); 577 dbg_nn_print("W'_x", &(Wprime->X.fp_val)); 578 dbg_nn_print("W'_y", &(Wprime->Y.fp_val)); 579 580 /* 7. Compute r' = W'_x mod q */ 581 ret = nn_mod(&r_prime, &(Wprime->X.fp_val), q); EG(ret, err); 582 583 /* 8. Check r and r' are the same */ 584 ret = nn_cmp(r, &r_prime, &cmp); EG(ret, err); 585 ret = (cmp == 0) ? 0 : -1; 586 587 err: 588 nn_uninit(&h); 589 nn_uninit(&r_prime); 590 nn_uninit(&e); 591 nn_uninit(&v); 592 nn_uninit(&u); 593 prj_pt_uninit(&vY); 594 prj_pt_uninit(&uG); 595 596 /* 597 * We can now clear data part of the context. This will clear 598 * magic and avoid further reuse of the whole context. 599 */ 600 if(ctx != NULL){ 601 IGNORE_RET_VAL(local_memset(&(ctx->verify_data.ecrdsa), 0, 602 sizeof(ecrdsa_verify_data))); 603 } 604 605 /* Clean what remains on the stack */ 606 PTR_NULLIFY(Wprime); 607 PTR_NULLIFY(G); 608 PTR_NULLIFY(Y); 609 PTR_NULLIFY(q); 610 PTR_NULLIFY(r); 611 PTR_NULLIFY(s); 612 VAR_ZEROIFY(hsize); 613 614 return ret; 615 } 616 617 #else /* WITH_SIG_ECRDSA */ 618 619 /* 620 * Dummy definition to avoid the empty translation unit ISO C warning 621 */ 622 typedef int dummy; 623 #endif /* WITH_SIG_ECRDSA */ 624