1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/ec.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1085 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifdef FREEBL_NO_DEPEND 1.9 +#include "stubs.h" 1.10 +#endif 1.11 + 1.12 + 1.13 +#include "blapi.h" 1.14 +#include "prerr.h" 1.15 +#include "secerr.h" 1.16 +#include "secmpi.h" 1.17 +#include "secitem.h" 1.18 +#include "mplogic.h" 1.19 +#include "ec.h" 1.20 +#include "ecl.h" 1.21 + 1.22 +#ifndef NSS_DISABLE_ECC 1.23 + 1.24 +/* 1.25 + * Returns true if pointP is the point at infinity, false otherwise 1.26 + */ 1.27 +PRBool 1.28 +ec_point_at_infinity(SECItem *pointP) 1.29 +{ 1.30 + unsigned int i; 1.31 + 1.32 + for (i = 1; i < pointP->len; i++) { 1.33 + if (pointP->data[i] != 0x00) return PR_FALSE; 1.34 + } 1.35 + 1.36 + return PR_TRUE; 1.37 +} 1.38 + 1.39 +/* 1.40 + * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for 1.41 + * the curve whose parameters are encoded in params with base point G. 1.42 + */ 1.43 +SECStatus 1.44 +ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2, 1.45 + const SECItem *pointP, SECItem *pointQ) 1.46 +{ 1.47 + mp_int Px, Py, Qx, Qy; 1.48 + mp_int Gx, Gy, order, irreducible, a, b; 1.49 +#if 0 /* currently don't support non-named curves */ 1.50 + unsigned int irr_arr[5]; 1.51 +#endif 1.52 + ECGroup *group = NULL; 1.53 + SECStatus rv = SECFailure; 1.54 + mp_err err = MP_OKAY; 1.55 + int len; 1.56 + 1.57 +#if EC_DEBUG 1.58 + int i; 1.59 + char mpstr[256]; 1.60 + 1.61 + printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len); 1.62 + for (i = 0; i < params->DEREncoding.len; i++) 1.63 + printf("%02x:", params->DEREncoding.data[i]); 1.64 + printf("\n"); 1.65 + 1.66 + if (k1 != NULL) { 1.67 + mp_tohex(k1, mpstr); 1.68 + printf("ec_points_mul: scalar k1: %s\n", mpstr); 1.69 + mp_todecimal(k1, mpstr); 1.70 + printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr); 1.71 + } 1.72 + 1.73 + if (k2 != NULL) { 1.74 + mp_tohex(k2, mpstr); 1.75 + printf("ec_points_mul: scalar k2: %s\n", mpstr); 1.76 + mp_todecimal(k2, mpstr); 1.77 + printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr); 1.78 + } 1.79 + 1.80 + if (pointP != NULL) { 1.81 + printf("ec_points_mul: pointP [len=%d]:", pointP->len); 1.82 + for (i = 0; i < pointP->len; i++) 1.83 + printf("%02x:", pointP->data[i]); 1.84 + printf("\n"); 1.85 + } 1.86 +#endif 1.87 + 1.88 + /* NOTE: We only support uncompressed points for now */ 1.89 + len = (params->fieldID.size + 7) >> 3; 1.90 + if (pointP != NULL) { 1.91 + if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || 1.92 + (pointP->len != (2 * len + 1))) { 1.93 + PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); 1.94 + return SECFailure; 1.95 + }; 1.96 + } 1.97 + 1.98 + MP_DIGITS(&Px) = 0; 1.99 + MP_DIGITS(&Py) = 0; 1.100 + MP_DIGITS(&Qx) = 0; 1.101 + MP_DIGITS(&Qy) = 0; 1.102 + MP_DIGITS(&Gx) = 0; 1.103 + MP_DIGITS(&Gy) = 0; 1.104 + MP_DIGITS(&order) = 0; 1.105 + MP_DIGITS(&irreducible) = 0; 1.106 + MP_DIGITS(&a) = 0; 1.107 + MP_DIGITS(&b) = 0; 1.108 + CHECK_MPI_OK( mp_init(&Px) ); 1.109 + CHECK_MPI_OK( mp_init(&Py) ); 1.110 + CHECK_MPI_OK( mp_init(&Qx) ); 1.111 + CHECK_MPI_OK( mp_init(&Qy) ); 1.112 + CHECK_MPI_OK( mp_init(&Gx) ); 1.113 + CHECK_MPI_OK( mp_init(&Gy) ); 1.114 + CHECK_MPI_OK( mp_init(&order) ); 1.115 + CHECK_MPI_OK( mp_init(&irreducible) ); 1.116 + CHECK_MPI_OK( mp_init(&a) ); 1.117 + CHECK_MPI_OK( mp_init(&b) ); 1.118 + 1.119 + if ((k2 != NULL) && (pointP != NULL)) { 1.120 + /* Initialize Px and Py */ 1.121 + CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) ); 1.122 + CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) ); 1.123 + } 1.124 + 1.125 + /* construct from named params, if possible */ 1.126 + if (params->name != ECCurve_noName) { 1.127 + group = ECGroup_fromName(params->name); 1.128 + } 1.129 + 1.130 +#if 0 /* currently don't support non-named curves */ 1.131 + if (group == NULL) { 1.132 + /* Set up mp_ints containing the curve coefficients */ 1.133 + CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1, 1.134 + (mp_size) len) ); 1.135 + CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len, 1.136 + (mp_size) len) ); 1.137 + SECITEM_TO_MPINT( params->order, &order ); 1.138 + SECITEM_TO_MPINT( params->curve.a, &a ); 1.139 + SECITEM_TO_MPINT( params->curve.b, &b ); 1.140 + if (params->fieldID.type == ec_field_GFp) { 1.141 + SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible ); 1.142 + group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor); 1.143 + } else { 1.144 + SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible ); 1.145 + irr_arr[0] = params->fieldID.size; 1.146 + irr_arr[1] = params->fieldID.k1; 1.147 + irr_arr[2] = params->fieldID.k2; 1.148 + irr_arr[3] = params->fieldID.k3; 1.149 + irr_arr[4] = 0; 1.150 + group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor); 1.151 + } 1.152 + } 1.153 +#endif 1.154 + if (group == NULL) 1.155 + goto cleanup; 1.156 + 1.157 + if ((k2 != NULL) && (pointP != NULL)) { 1.158 + CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) ); 1.159 + } else { 1.160 + CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) ); 1.161 + } 1.162 + 1.163 + /* Construct the SECItem representation of point Q */ 1.164 + pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED; 1.165 + CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1, 1.166 + (mp_size) len) ); 1.167 + CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len, 1.168 + (mp_size) len) ); 1.169 + 1.170 + rv = SECSuccess; 1.171 + 1.172 +#if EC_DEBUG 1.173 + printf("ec_points_mul: pointQ [len=%d]:", pointQ->len); 1.174 + for (i = 0; i < pointQ->len; i++) 1.175 + printf("%02x:", pointQ->data[i]); 1.176 + printf("\n"); 1.177 +#endif 1.178 + 1.179 +cleanup: 1.180 + ECGroup_free(group); 1.181 + mp_clear(&Px); 1.182 + mp_clear(&Py); 1.183 + mp_clear(&Qx); 1.184 + mp_clear(&Qy); 1.185 + mp_clear(&Gx); 1.186 + mp_clear(&Gy); 1.187 + mp_clear(&order); 1.188 + mp_clear(&irreducible); 1.189 + mp_clear(&a); 1.190 + mp_clear(&b); 1.191 + if (err) { 1.192 + MP_TO_SEC_ERROR(err); 1.193 + rv = SECFailure; 1.194 + } 1.195 + 1.196 + return rv; 1.197 +} 1.198 +#endif /* NSS_DISABLE_ECC */ 1.199 + 1.200 +/* Generates a new EC key pair. The private key is a supplied 1.201 + * value and the public key is the result of performing a scalar 1.202 + * point multiplication of that value with the curve's base point. 1.203 + */ 1.204 +SECStatus 1.205 +ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, 1.206 + const unsigned char *privKeyBytes, int privKeyLen) 1.207 +{ 1.208 + SECStatus rv = SECFailure; 1.209 +#ifndef NSS_DISABLE_ECC 1.210 + PLArenaPool *arena; 1.211 + ECPrivateKey *key; 1.212 + mp_int k; 1.213 + mp_err err = MP_OKAY; 1.214 + int len; 1.215 + 1.216 +#if EC_DEBUG 1.217 + printf("ec_NewKey called\n"); 1.218 +#endif 1.219 + MP_DIGITS(&k) = 0; 1.220 + 1.221 + if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) { 1.222 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.223 + return SECFailure; 1.224 + } 1.225 + 1.226 + /* Initialize an arena for the EC key. */ 1.227 + if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) 1.228 + return SECFailure; 1.229 + 1.230 + key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey)); 1.231 + if (!key) { 1.232 + PORT_FreeArena(arena, PR_TRUE); 1.233 + return SECFailure; 1.234 + } 1.235 + 1.236 + /* Set the version number (SEC 1 section C.4 says it should be 1) */ 1.237 + SECITEM_AllocItem(arena, &key->version, 1); 1.238 + key->version.data[0] = 1; 1.239 + 1.240 + /* Copy all of the fields from the ECParams argument to the 1.241 + * ECParams structure within the private key. 1.242 + */ 1.243 + key->ecParams.arena = arena; 1.244 + key->ecParams.type = ecParams->type; 1.245 + key->ecParams.fieldID.size = ecParams->fieldID.size; 1.246 + key->ecParams.fieldID.type = ecParams->fieldID.type; 1.247 + if (ecParams->fieldID.type == ec_field_GFp) { 1.248 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime, 1.249 + &ecParams->fieldID.u.prime)); 1.250 + } else { 1.251 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly, 1.252 + &ecParams->fieldID.u.poly)); 1.253 + } 1.254 + key->ecParams.fieldID.k1 = ecParams->fieldID.k1; 1.255 + key->ecParams.fieldID.k2 = ecParams->fieldID.k2; 1.256 + key->ecParams.fieldID.k3 = ecParams->fieldID.k3; 1.257 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a, 1.258 + &ecParams->curve.a)); 1.259 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b, 1.260 + &ecParams->curve.b)); 1.261 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed, 1.262 + &ecParams->curve.seed)); 1.263 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base, 1.264 + &ecParams->base)); 1.265 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order, 1.266 + &ecParams->order)); 1.267 + key->ecParams.cofactor = ecParams->cofactor; 1.268 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding, 1.269 + &ecParams->DEREncoding)); 1.270 + key->ecParams.name = ecParams->name; 1.271 + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID, 1.272 + &ecParams->curveOID)); 1.273 + 1.274 + len = (ecParams->fieldID.size + 7) >> 3; 1.275 + SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1); 1.276 + len = ecParams->order.len; 1.277 + SECITEM_AllocItem(arena, &key->privateValue, len); 1.278 + 1.279 + /* Copy private key */ 1.280 + if (privKeyLen >= len) { 1.281 + memcpy(key->privateValue.data, privKeyBytes, len); 1.282 + } else { 1.283 + memset(key->privateValue.data, 0, (len - privKeyLen)); 1.284 + memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen); 1.285 + } 1.286 + 1.287 + /* Compute corresponding public key */ 1.288 + CHECK_MPI_OK( mp_init(&k) ); 1.289 + CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data, 1.290 + (mp_size) len) ); 1.291 + 1.292 + rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue)); 1.293 + if (rv != SECSuccess) goto cleanup; 1.294 + *privKey = key; 1.295 + 1.296 +cleanup: 1.297 + mp_clear(&k); 1.298 + if (rv) 1.299 + PORT_FreeArena(arena, PR_TRUE); 1.300 + 1.301 +#if EC_DEBUG 1.302 + printf("ec_NewKey returning %s\n", 1.303 + (rv == SECSuccess) ? "success" : "failure"); 1.304 +#endif 1.305 +#else 1.306 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.307 +#endif /* NSS_DISABLE_ECC */ 1.308 + 1.309 + return rv; 1.310 + 1.311 +} 1.312 + 1.313 +/* Generates a new EC key pair. The private key is a supplied 1.314 + * random value (in seed) and the public key is the result of 1.315 + * performing a scalar point multiplication of that value with 1.316 + * the curve's base point. 1.317 + */ 1.318 +SECStatus 1.319 +EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, 1.320 + const unsigned char *seed, int seedlen) 1.321 +{ 1.322 + SECStatus rv = SECFailure; 1.323 +#ifndef NSS_DISABLE_ECC 1.324 + rv = ec_NewKey(ecParams, privKey, seed, seedlen); 1.325 +#else 1.326 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.327 +#endif /* NSS_DISABLE_ECC */ 1.328 + return rv; 1.329 +} 1.330 + 1.331 +#ifndef NSS_DISABLE_ECC 1.332 +/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62, 1.333 + * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the 1.334 + * random number generator. 1.335 + * 1.336 + * Parameters 1.337 + * - order: a buffer that holds the curve's group order 1.338 + * - len: the length in octets of the order buffer 1.339 + * 1.340 + * Return Value 1.341 + * Returns a buffer of len octets that holds the private key. The caller 1.342 + * is responsible for freeing the buffer with PORT_ZFree. 1.343 + */ 1.344 +static unsigned char * 1.345 +ec_GenerateRandomPrivateKey(const unsigned char *order, int len) 1.346 +{ 1.347 + SECStatus rv = SECSuccess; 1.348 + mp_err err; 1.349 + unsigned char *privKeyBytes = NULL; 1.350 + mp_int privKeyVal, order_1, one; 1.351 + 1.352 + MP_DIGITS(&privKeyVal) = 0; 1.353 + MP_DIGITS(&order_1) = 0; 1.354 + MP_DIGITS(&one) = 0; 1.355 + CHECK_MPI_OK( mp_init(&privKeyVal) ); 1.356 + CHECK_MPI_OK( mp_init(&order_1) ); 1.357 + CHECK_MPI_OK( mp_init(&one) ); 1.358 + 1.359 + /* Generates 2*len random bytes using the global random bit generator 1.360 + * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then 1.361 + * reduces modulo the group order. 1.362 + */ 1.363 + if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup; 1.364 + CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) ); 1.365 + CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) ); 1.366 + CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) ); 1.367 + CHECK_MPI_OK( mp_set_int(&one, 1) ); 1.368 + CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) ); 1.369 + CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) ); 1.370 + CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) ); 1.371 + CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) ); 1.372 + memset(privKeyBytes+len, 0, len); 1.373 +cleanup: 1.374 + mp_clear(&privKeyVal); 1.375 + mp_clear(&order_1); 1.376 + mp_clear(&one); 1.377 + if (err < MP_OKAY) { 1.378 + MP_TO_SEC_ERROR(err); 1.379 + rv = SECFailure; 1.380 + } 1.381 + if (rv != SECSuccess && privKeyBytes) { 1.382 + PORT_Free(privKeyBytes); 1.383 + privKeyBytes = NULL; 1.384 + } 1.385 + return privKeyBytes; 1.386 +} 1.387 +#endif /* NSS_DISABLE_ECC */ 1.388 + 1.389 +/* Generates a new EC key pair. The private key is a random value and 1.390 + * the public key is the result of performing a scalar point multiplication 1.391 + * of that value with the curve's base point. 1.392 + */ 1.393 +SECStatus 1.394 +EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey) 1.395 +{ 1.396 + SECStatus rv = SECFailure; 1.397 +#ifndef NSS_DISABLE_ECC 1.398 + int len; 1.399 + unsigned char *privKeyBytes = NULL; 1.400 + 1.401 + if (!ecParams) { 1.402 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.403 + return SECFailure; 1.404 + } 1.405 + 1.406 + len = ecParams->order.len; 1.407 + privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len); 1.408 + if (privKeyBytes == NULL) goto cleanup; 1.409 + /* generate public key */ 1.410 + CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) ); 1.411 + 1.412 +cleanup: 1.413 + if (privKeyBytes) { 1.414 + PORT_ZFree(privKeyBytes, len); 1.415 + } 1.416 +#if EC_DEBUG 1.417 + printf("EC_NewKey returning %s\n", 1.418 + (rv == SECSuccess) ? "success" : "failure"); 1.419 +#endif 1.420 +#else 1.421 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.422 +#endif /* NSS_DISABLE_ECC */ 1.423 + 1.424 + return rv; 1.425 +} 1.426 + 1.427 +/* Validates an EC public key as described in Section 5.2.2 of 1.428 + * X9.62. The ECDH primitive when used without the cofactor does 1.429 + * not address small subgroup attacks, which may occur when the 1.430 + * public key is not valid. These attacks can be prevented by 1.431 + * validating the public key before using ECDH. 1.432 + */ 1.433 +SECStatus 1.434 +EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue) 1.435 +{ 1.436 +#ifndef NSS_DISABLE_ECC 1.437 + mp_int Px, Py; 1.438 + ECGroup *group = NULL; 1.439 + SECStatus rv = SECFailure; 1.440 + mp_err err = MP_OKAY; 1.441 + int len; 1.442 + 1.443 + if (!ecParams || !publicValue) { 1.444 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.445 + return SECFailure; 1.446 + } 1.447 + 1.448 + /* NOTE: We only support uncompressed points for now */ 1.449 + len = (ecParams->fieldID.size + 7) >> 3; 1.450 + if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) { 1.451 + PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); 1.452 + return SECFailure; 1.453 + } else if (publicValue->len != (2 * len + 1)) { 1.454 + PORT_SetError(SEC_ERROR_BAD_KEY); 1.455 + return SECFailure; 1.456 + } 1.457 + 1.458 + MP_DIGITS(&Px) = 0; 1.459 + MP_DIGITS(&Py) = 0; 1.460 + CHECK_MPI_OK( mp_init(&Px) ); 1.461 + CHECK_MPI_OK( mp_init(&Py) ); 1.462 + 1.463 + /* Initialize Px and Py */ 1.464 + CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) ); 1.465 + CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) ); 1.466 + 1.467 + /* construct from named params */ 1.468 + group = ECGroup_fromName(ecParams->name); 1.469 + if (group == NULL) { 1.470 + /* 1.471 + * ECGroup_fromName fails if ecParams->name is not a valid 1.472 + * ECCurveName value, or if we run out of memory, or perhaps 1.473 + * for other reasons. Unfortunately if ecParams->name is a 1.474 + * valid ECCurveName value, we don't know what the right error 1.475 + * code should be because ECGroup_fromName doesn't return an 1.476 + * error code to the caller. Set err to MP_UNDEF because 1.477 + * that's what ECGroup_fromName uses internally. 1.478 + */ 1.479 + if ((ecParams->name <= ECCurve_noName) || 1.480 + (ecParams->name >= ECCurve_pastLastCurve)) { 1.481 + err = MP_BADARG; 1.482 + } else { 1.483 + err = MP_UNDEF; 1.484 + } 1.485 + goto cleanup; 1.486 + } 1.487 + 1.488 + /* validate public point */ 1.489 + if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) { 1.490 + if (err == MP_NO) { 1.491 + PORT_SetError(SEC_ERROR_BAD_KEY); 1.492 + rv = SECFailure; 1.493 + err = MP_OKAY; /* don't change the error code */ 1.494 + } 1.495 + goto cleanup; 1.496 + } 1.497 + 1.498 + rv = SECSuccess; 1.499 + 1.500 +cleanup: 1.501 + ECGroup_free(group); 1.502 + mp_clear(&Px); 1.503 + mp_clear(&Py); 1.504 + if (err) { 1.505 + MP_TO_SEC_ERROR(err); 1.506 + rv = SECFailure; 1.507 + } 1.508 + return rv; 1.509 +#else 1.510 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.511 + return SECFailure; 1.512 +#endif /* NSS_DISABLE_ECC */ 1.513 +} 1.514 + 1.515 +/* 1.516 +** Performs an ECDH key derivation by computing the scalar point 1.517 +** multiplication of privateValue and publicValue (with or without the 1.518 +** cofactor) and returns the x-coordinate of the resulting elliptic 1.519 +** curve point in derived secret. If successful, derivedSecret->data 1.520 +** is set to the address of the newly allocated buffer containing the 1.521 +** derived secret, and derivedSecret->len is the size of the secret 1.522 +** produced. It is the caller's responsibility to free the allocated 1.523 +** buffer containing the derived secret. 1.524 +*/ 1.525 +SECStatus 1.526 +ECDH_Derive(SECItem *publicValue, 1.527 + ECParams *ecParams, 1.528 + SECItem *privateValue, 1.529 + PRBool withCofactor, 1.530 + SECItem *derivedSecret) 1.531 +{ 1.532 + SECStatus rv = SECFailure; 1.533 +#ifndef NSS_DISABLE_ECC 1.534 + unsigned int len = 0; 1.535 + SECItem pointQ = {siBuffer, NULL, 0}; 1.536 + mp_int k; /* to hold the private value */ 1.537 + mp_int cofactor; 1.538 + mp_err err = MP_OKAY; 1.539 +#if EC_DEBUG 1.540 + int i; 1.541 +#endif 1.542 + 1.543 + if (!publicValue || !ecParams || !privateValue || 1.544 + !derivedSecret) { 1.545 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.546 + return SECFailure; 1.547 + } 1.548 + 1.549 + MP_DIGITS(&k) = 0; 1.550 + memset(derivedSecret, 0, sizeof *derivedSecret); 1.551 + len = (ecParams->fieldID.size + 7) >> 3; 1.552 + pointQ.len = 2*len + 1; 1.553 + if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup; 1.554 + 1.555 + CHECK_MPI_OK( mp_init(&k) ); 1.556 + CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data, 1.557 + (mp_size) privateValue->len) ); 1.558 + 1.559 + if (withCofactor && (ecParams->cofactor != 1)) { 1.560 + /* multiply k with the cofactor */ 1.561 + MP_DIGITS(&cofactor) = 0; 1.562 + CHECK_MPI_OK( mp_init(&cofactor) ); 1.563 + mp_set(&cofactor, ecParams->cofactor); 1.564 + CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) ); 1.565 + } 1.566 + 1.567 + /* Multiply our private key and peer's public point */ 1.568 + if (ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess) 1.569 + goto cleanup; 1.570 + if (ec_point_at_infinity(&pointQ)) { 1.571 + PORT_SetError(SEC_ERROR_BAD_KEY); /* XXX better error code? */ 1.572 + goto cleanup; 1.573 + } 1.574 + 1.575 + /* Allocate memory for the derived secret and copy 1.576 + * the x co-ordinate of pointQ into it. 1.577 + */ 1.578 + SECITEM_AllocItem(NULL, derivedSecret, len); 1.579 + memcpy(derivedSecret->data, pointQ.data + 1, len); 1.580 + 1.581 + rv = SECSuccess; 1.582 + 1.583 +#if EC_DEBUG 1.584 + printf("derived_secret:\n"); 1.585 + for (i = 0; i < derivedSecret->len; i++) 1.586 + printf("%02x:", derivedSecret->data[i]); 1.587 + printf("\n"); 1.588 +#endif 1.589 + 1.590 +cleanup: 1.591 + mp_clear(&k); 1.592 + 1.593 + if (err) { 1.594 + MP_TO_SEC_ERROR(err); 1.595 + } 1.596 + 1.597 + if (pointQ.data) { 1.598 + PORT_ZFree(pointQ.data, 2*len + 1); 1.599 + } 1.600 +#else 1.601 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.602 +#endif /* NSS_DISABLE_ECC */ 1.603 + 1.604 + return rv; 1.605 +} 1.606 + 1.607 +/* Computes the ECDSA signature (a concatenation of two values r and s) 1.608 + * on the digest using the given key and the random value kb (used in 1.609 + * computing s). 1.610 + */ 1.611 +SECStatus 1.612 +ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, 1.613 + const SECItem *digest, const unsigned char *kb, const int kblen) 1.614 +{ 1.615 + SECStatus rv = SECFailure; 1.616 +#ifndef NSS_DISABLE_ECC 1.617 + mp_int x1; 1.618 + mp_int d, k; /* private key, random integer */ 1.619 + mp_int r, s; /* tuple (r, s) is the signature */ 1.620 + mp_int n; 1.621 + mp_err err = MP_OKAY; 1.622 + ECParams *ecParams = NULL; 1.623 + SECItem kGpoint = { siBuffer, NULL, 0}; 1.624 + int flen = 0; /* length in bytes of the field size */ 1.625 + unsigned olen; /* length in bytes of the base point order */ 1.626 + unsigned obits; /* length in bits of the base point order */ 1.627 + 1.628 +#if EC_DEBUG 1.629 + char mpstr[256]; 1.630 +#endif 1.631 + 1.632 + /* Initialize MPI integers. */ 1.633 + /* must happen before the first potential call to cleanup */ 1.634 + MP_DIGITS(&x1) = 0; 1.635 + MP_DIGITS(&d) = 0; 1.636 + MP_DIGITS(&k) = 0; 1.637 + MP_DIGITS(&r) = 0; 1.638 + MP_DIGITS(&s) = 0; 1.639 + MP_DIGITS(&n) = 0; 1.640 + 1.641 + /* Check args */ 1.642 + if (!key || !signature || !digest || !kb || (kblen < 0)) { 1.643 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.644 + goto cleanup; 1.645 + } 1.646 + 1.647 + ecParams = &(key->ecParams); 1.648 + flen = (ecParams->fieldID.size + 7) >> 3; 1.649 + olen = ecParams->order.len; 1.650 + if (signature->data == NULL) { 1.651 + /* a call to get the signature length only */ 1.652 + goto finish; 1.653 + } 1.654 + if (signature->len < 2*olen) { 1.655 + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 1.656 + goto cleanup; 1.657 + } 1.658 + 1.659 + 1.660 + CHECK_MPI_OK( mp_init(&x1) ); 1.661 + CHECK_MPI_OK( mp_init(&d) ); 1.662 + CHECK_MPI_OK( mp_init(&k) ); 1.663 + CHECK_MPI_OK( mp_init(&r) ); 1.664 + CHECK_MPI_OK( mp_init(&s) ); 1.665 + CHECK_MPI_OK( mp_init(&n) ); 1.666 + 1.667 + SECITEM_TO_MPINT( ecParams->order, &n ); 1.668 + SECITEM_TO_MPINT( key->privateValue, &d ); 1.669 + 1.670 + CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) ); 1.671 + /* Make sure k is in the interval [1, n-1] */ 1.672 + if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) { 1.673 +#if EC_DEBUG 1.674 + printf("k is outside [1, n-1]\n"); 1.675 + mp_tohex(&k, mpstr); 1.676 + printf("k : %s \n", mpstr); 1.677 + mp_tohex(&n, mpstr); 1.678 + printf("n : %s \n", mpstr); 1.679 +#endif 1.680 + PORT_SetError(SEC_ERROR_NEED_RANDOM); 1.681 + goto cleanup; 1.682 + } 1.683 + 1.684 + /* 1.685 + ** We do not want timing information to leak the length of k, 1.686 + ** so we compute k*G using an equivalent scalar of fixed 1.687 + ** bit-length. 1.688 + ** Fix based on patch for ECDSA timing attack in the paper 1.689 + ** by Billy Bob Brumley and Nicola Tuveri at 1.690 + ** http://eprint.iacr.org/2011/232 1.691 + ** 1.692 + ** How do we convert k to a value of a fixed bit-length? 1.693 + ** k starts off as an integer satisfying 0 <= k < n. Hence, 1.694 + ** n <= k+n < 2n, which means k+n has either the same number 1.695 + ** of bits as n or one more bit than n. If k+n has the same 1.696 + ** number of bits as n, the second addition ensures that the 1.697 + ** final value has exactly one more bit than n. Thus, we 1.698 + ** always end up with a value that exactly one more bit than n. 1.699 + */ 1.700 + CHECK_MPI_OK( mp_add(&k, &n, &k) ); 1.701 + if (mpl_significant_bits(&k) <= mpl_significant_bits(&n)) { 1.702 + CHECK_MPI_OK( mp_add(&k, &n, &k) ); 1.703 + } 1.704 + 1.705 + /* 1.706 + ** ANSI X9.62, Section 5.3.2, Step 2 1.707 + ** 1.708 + ** Compute kG 1.709 + */ 1.710 + kGpoint.len = 2*flen + 1; 1.711 + kGpoint.data = PORT_Alloc(2*flen + 1); 1.712 + if ((kGpoint.data == NULL) || 1.713 + (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) 1.714 + != SECSuccess)) 1.715 + goto cleanup; 1.716 + 1.717 + /* 1.718 + ** ANSI X9.62, Section 5.3.3, Step 1 1.719 + ** 1.720 + ** Extract the x co-ordinate of kG into x1 1.721 + */ 1.722 + CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, 1.723 + (mp_size) flen) ); 1.724 + 1.725 + /* 1.726 + ** ANSI X9.62, Section 5.3.3, Step 2 1.727 + ** 1.728 + ** r = x1 mod n NOTE: n is the order of the curve 1.729 + */ 1.730 + CHECK_MPI_OK( mp_mod(&x1, &n, &r) ); 1.731 + 1.732 + /* 1.733 + ** ANSI X9.62, Section 5.3.3, Step 3 1.734 + ** 1.735 + ** verify r != 0 1.736 + */ 1.737 + if (mp_cmp_z(&r) == 0) { 1.738 + PORT_SetError(SEC_ERROR_NEED_RANDOM); 1.739 + goto cleanup; 1.740 + } 1.741 + 1.742 + /* 1.743 + ** ANSI X9.62, Section 5.3.3, Step 4 1.744 + ** 1.745 + ** s = (k**-1 * (HASH(M) + d*r)) mod n 1.746 + */ 1.747 + SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */ 1.748 + 1.749 + /* In the definition of EC signing, digests are truncated 1.750 + * to the length of n in bits. 1.751 + * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ 1.752 + CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) ); 1.753 + if (digest->len*8 > obits) { 1.754 + mpl_rsh(&s,&s,digest->len*8 - obits); 1.755 + } 1.756 + 1.757 +#if EC_DEBUG 1.758 + mp_todecimal(&n, mpstr); 1.759 + printf("n : %s (dec)\n", mpstr); 1.760 + mp_todecimal(&d, mpstr); 1.761 + printf("d : %s (dec)\n", mpstr); 1.762 + mp_tohex(&x1, mpstr); 1.763 + printf("x1: %s\n", mpstr); 1.764 + mp_todecimal(&s, mpstr); 1.765 + printf("digest: %s (decimal)\n", mpstr); 1.766 + mp_todecimal(&r, mpstr); 1.767 + printf("r : %s (dec)\n", mpstr); 1.768 + mp_tohex(&r, mpstr); 1.769 + printf("r : %s\n", mpstr); 1.770 +#endif 1.771 + 1.772 + CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */ 1.773 + CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */ 1.774 + CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */ 1.775 + CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */ 1.776 + 1.777 +#if EC_DEBUG 1.778 + mp_todecimal(&s, mpstr); 1.779 + printf("s : %s (dec)\n", mpstr); 1.780 + mp_tohex(&s, mpstr); 1.781 + printf("s : %s\n", mpstr); 1.782 +#endif 1.783 + 1.784 + /* 1.785 + ** ANSI X9.62, Section 5.3.3, Step 5 1.786 + ** 1.787 + ** verify s != 0 1.788 + */ 1.789 + if (mp_cmp_z(&s) == 0) { 1.790 + PORT_SetError(SEC_ERROR_NEED_RANDOM); 1.791 + goto cleanup; 1.792 + } 1.793 + 1.794 + /* 1.795 + ** 1.796 + ** Signature is tuple (r, s) 1.797 + */ 1.798 + CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) ); 1.799 + CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) ); 1.800 +finish: 1.801 + signature->len = 2*olen; 1.802 + 1.803 + rv = SECSuccess; 1.804 + err = MP_OKAY; 1.805 +cleanup: 1.806 + mp_clear(&x1); 1.807 + mp_clear(&d); 1.808 + mp_clear(&k); 1.809 + mp_clear(&r); 1.810 + mp_clear(&s); 1.811 + mp_clear(&n); 1.812 + 1.813 + if (kGpoint.data) { 1.814 + PORT_ZFree(kGpoint.data, 2*flen + 1); 1.815 + } 1.816 + 1.817 + if (err) { 1.818 + MP_TO_SEC_ERROR(err); 1.819 + rv = SECFailure; 1.820 + } 1.821 + 1.822 +#if EC_DEBUG 1.823 + printf("ECDSA signing with seed %s\n", 1.824 + (rv == SECSuccess) ? "succeeded" : "failed"); 1.825 +#endif 1.826 +#else 1.827 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.828 +#endif /* NSS_DISABLE_ECC */ 1.829 + 1.830 + return rv; 1.831 +} 1.832 + 1.833 +/* 1.834 +** Computes the ECDSA signature on the digest using the given key 1.835 +** and a random seed. 1.836 +*/ 1.837 +SECStatus 1.838 +ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest) 1.839 +{ 1.840 + SECStatus rv = SECFailure; 1.841 +#ifndef NSS_DISABLE_ECC 1.842 + int len; 1.843 + unsigned char *kBytes= NULL; 1.844 + 1.845 + if (!key) { 1.846 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.847 + return SECFailure; 1.848 + } 1.849 + 1.850 + /* Generate random value k */ 1.851 + len = key->ecParams.order.len; 1.852 + kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len); 1.853 + if (kBytes == NULL) goto cleanup; 1.854 + 1.855 + /* Generate ECDSA signature with the specified k value */ 1.856 + rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len); 1.857 + 1.858 +cleanup: 1.859 + if (kBytes) { 1.860 + PORT_ZFree(kBytes, len); 1.861 + } 1.862 + 1.863 +#if EC_DEBUG 1.864 + printf("ECDSA signing %s\n", 1.865 + (rv == SECSuccess) ? "succeeded" : "failed"); 1.866 +#endif 1.867 +#else 1.868 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.869 +#endif /* NSS_DISABLE_ECC */ 1.870 + 1.871 + return rv; 1.872 +} 1.873 + 1.874 +/* 1.875 +** Checks the signature on the given digest using the key provided. 1.876 +** 1.877 +** The key argument must represent a valid EC public key (a point on 1.878 +** the relevant curve). If it is not a valid point, then the behavior 1.879 +** of this function is undefined. In cases where a public key might 1.880 +** not be valid, use EC_ValidatePublicKey to check. 1.881 +*/ 1.882 +SECStatus 1.883 +ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, 1.884 + const SECItem *digest) 1.885 +{ 1.886 + SECStatus rv = SECFailure; 1.887 +#ifndef NSS_DISABLE_ECC 1.888 + mp_int r_, s_; /* tuple (r', s') is received signature) */ 1.889 + mp_int c, u1, u2, v; /* intermediate values used in verification */ 1.890 + mp_int x1; 1.891 + mp_int n; 1.892 + mp_err err = MP_OKAY; 1.893 + ECParams *ecParams = NULL; 1.894 + SECItem pointC = { siBuffer, NULL, 0 }; 1.895 + int slen; /* length in bytes of a half signature (r or s) */ 1.896 + int flen; /* length in bytes of the field size */ 1.897 + unsigned olen; /* length in bytes of the base point order */ 1.898 + unsigned obits; /* length in bits of the base point order */ 1.899 + 1.900 +#if EC_DEBUG 1.901 + char mpstr[256]; 1.902 + printf("ECDSA verification called\n"); 1.903 +#endif 1.904 + 1.905 + /* Initialize MPI integers. */ 1.906 + /* must happen before the first potential call to cleanup */ 1.907 + MP_DIGITS(&r_) = 0; 1.908 + MP_DIGITS(&s_) = 0; 1.909 + MP_DIGITS(&c) = 0; 1.910 + MP_DIGITS(&u1) = 0; 1.911 + MP_DIGITS(&u2) = 0; 1.912 + MP_DIGITS(&x1) = 0; 1.913 + MP_DIGITS(&v) = 0; 1.914 + MP_DIGITS(&n) = 0; 1.915 + 1.916 + /* Check args */ 1.917 + if (!key || !signature || !digest) { 1.918 + PORT_SetError(SEC_ERROR_INVALID_ARGS); 1.919 + goto cleanup; 1.920 + } 1.921 + 1.922 + ecParams = &(key->ecParams); 1.923 + flen = (ecParams->fieldID.size + 7) >> 3; 1.924 + olen = ecParams->order.len; 1.925 + if (signature->len == 0 || signature->len%2 != 0 || 1.926 + signature->len > 2*olen) { 1.927 + PORT_SetError(SEC_ERROR_INPUT_LEN); 1.928 + goto cleanup; 1.929 + } 1.930 + slen = signature->len/2; 1.931 + 1.932 + SECITEM_AllocItem(NULL, &pointC, 2*flen + 1); 1.933 + if (pointC.data == NULL) 1.934 + goto cleanup; 1.935 + 1.936 + CHECK_MPI_OK( mp_init(&r_) ); 1.937 + CHECK_MPI_OK( mp_init(&s_) ); 1.938 + CHECK_MPI_OK( mp_init(&c) ); 1.939 + CHECK_MPI_OK( mp_init(&u1) ); 1.940 + CHECK_MPI_OK( mp_init(&u2) ); 1.941 + CHECK_MPI_OK( mp_init(&x1) ); 1.942 + CHECK_MPI_OK( mp_init(&v) ); 1.943 + CHECK_MPI_OK( mp_init(&n) ); 1.944 + 1.945 + /* 1.946 + ** Convert received signature (r', s') into MPI integers. 1.947 + */ 1.948 + CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) ); 1.949 + CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) ); 1.950 + 1.951 + /* 1.952 + ** ANSI X9.62, Section 5.4.2, Steps 1 and 2 1.953 + ** 1.954 + ** Verify that 0 < r' < n and 0 < s' < n 1.955 + */ 1.956 + SECITEM_TO_MPINT(ecParams->order, &n); 1.957 + if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || 1.958 + mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) { 1.959 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.960 + goto cleanup; /* will return rv == SECFailure */ 1.961 + } 1.962 + 1.963 + /* 1.964 + ** ANSI X9.62, Section 5.4.2, Step 3 1.965 + ** 1.966 + ** c = (s')**-1 mod n 1.967 + */ 1.968 + CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */ 1.969 + 1.970 + /* 1.971 + ** ANSI X9.62, Section 5.4.2, Step 4 1.972 + ** 1.973 + ** u1 = ((HASH(M')) * c) mod n 1.974 + */ 1.975 + SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */ 1.976 + 1.977 + /* In the definition of EC signing, digests are truncated 1.978 + * to the length of n in bits. 1.979 + * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ 1.980 + CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) ); 1.981 + if (digest->len*8 > obits) { /* u1 = HASH(M') */ 1.982 + mpl_rsh(&u1,&u1,digest->len*8 - obits); 1.983 + } 1.984 + 1.985 +#if EC_DEBUG 1.986 + mp_todecimal(&r_, mpstr); 1.987 + printf("r_: %s (dec)\n", mpstr); 1.988 + mp_todecimal(&s_, mpstr); 1.989 + printf("s_: %s (dec)\n", mpstr); 1.990 + mp_todecimal(&c, mpstr); 1.991 + printf("c : %s (dec)\n", mpstr); 1.992 + mp_todecimal(&u1, mpstr); 1.993 + printf("digest: %s (dec)\n", mpstr); 1.994 +#endif 1.995 + 1.996 + CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */ 1.997 + 1.998 + /* 1.999 + ** ANSI X9.62, Section 5.4.2, Step 4 1.1000 + ** 1.1001 + ** u2 = ((r') * c) mod n 1.1002 + */ 1.1003 + CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) ); 1.1004 + 1.1005 + /* 1.1006 + ** ANSI X9.62, Section 5.4.3, Step 1 1.1007 + ** 1.1008 + ** Compute u1*G + u2*Q 1.1009 + ** Here, A = u1.G B = u2.Q and C = A + B 1.1010 + ** If the result, C, is the point at infinity, reject the signature 1.1011 + */ 1.1012 + if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) 1.1013 + != SECSuccess) { 1.1014 + rv = SECFailure; 1.1015 + goto cleanup; 1.1016 + } 1.1017 + if (ec_point_at_infinity(&pointC)) { 1.1018 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.1019 + rv = SECFailure; 1.1020 + goto cleanup; 1.1021 + } 1.1022 + 1.1023 + CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) ); 1.1024 + 1.1025 + /* 1.1026 + ** ANSI X9.62, Section 5.4.4, Step 2 1.1027 + ** 1.1028 + ** v = x1 mod n 1.1029 + */ 1.1030 + CHECK_MPI_OK( mp_mod(&x1, &n, &v) ); 1.1031 + 1.1032 +#if EC_DEBUG 1.1033 + mp_todecimal(&r_, mpstr); 1.1034 + printf("r_: %s (dec)\n", mpstr); 1.1035 + mp_todecimal(&v, mpstr); 1.1036 + printf("v : %s (dec)\n", mpstr); 1.1037 +#endif 1.1038 + 1.1039 + /* 1.1040 + ** ANSI X9.62, Section 5.4.4, Step 3 1.1041 + ** 1.1042 + ** Verification: v == r' 1.1043 + */ 1.1044 + if (mp_cmp(&v, &r_)) { 1.1045 + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); 1.1046 + rv = SECFailure; /* Signature failed to verify. */ 1.1047 + } else { 1.1048 + rv = SECSuccess; /* Signature verified. */ 1.1049 + } 1.1050 + 1.1051 +#if EC_DEBUG 1.1052 + mp_todecimal(&u1, mpstr); 1.1053 + printf("u1: %s (dec)\n", mpstr); 1.1054 + mp_todecimal(&u2, mpstr); 1.1055 + printf("u2: %s (dec)\n", mpstr); 1.1056 + mp_tohex(&x1, mpstr); 1.1057 + printf("x1: %s\n", mpstr); 1.1058 + mp_todecimal(&v, mpstr); 1.1059 + printf("v : %s (dec)\n", mpstr); 1.1060 +#endif 1.1061 + 1.1062 +cleanup: 1.1063 + mp_clear(&r_); 1.1064 + mp_clear(&s_); 1.1065 + mp_clear(&c); 1.1066 + mp_clear(&u1); 1.1067 + mp_clear(&u2); 1.1068 + mp_clear(&x1); 1.1069 + mp_clear(&v); 1.1070 + mp_clear(&n); 1.1071 + 1.1072 + if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE); 1.1073 + if (err) { 1.1074 + MP_TO_SEC_ERROR(err); 1.1075 + rv = SECFailure; 1.1076 + } 1.1077 + 1.1078 +#if EC_DEBUG 1.1079 + printf("ECDSA verification %s\n", 1.1080 + (rv == SECSuccess) ? "succeeded" : "failed"); 1.1081 +#endif 1.1082 +#else 1.1083 + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); 1.1084 +#endif /* NSS_DISABLE_ECC */ 1.1085 + 1.1086 + return rv; 1.1087 +} 1.1088 +