security/nss/lib/freebl/ec.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifdef FREEBL_NO_DEPEND
michael@0 6 #include "stubs.h"
michael@0 7 #endif
michael@0 8
michael@0 9
michael@0 10 #include "blapi.h"
michael@0 11 #include "prerr.h"
michael@0 12 #include "secerr.h"
michael@0 13 #include "secmpi.h"
michael@0 14 #include "secitem.h"
michael@0 15 #include "mplogic.h"
michael@0 16 #include "ec.h"
michael@0 17 #include "ecl.h"
michael@0 18
michael@0 19 #ifndef NSS_DISABLE_ECC
michael@0 20
michael@0 21 /*
michael@0 22 * Returns true if pointP is the point at infinity, false otherwise
michael@0 23 */
michael@0 24 PRBool
michael@0 25 ec_point_at_infinity(SECItem *pointP)
michael@0 26 {
michael@0 27 unsigned int i;
michael@0 28
michael@0 29 for (i = 1; i < pointP->len; i++) {
michael@0 30 if (pointP->data[i] != 0x00) return PR_FALSE;
michael@0 31 }
michael@0 32
michael@0 33 return PR_TRUE;
michael@0 34 }
michael@0 35
michael@0 36 /*
michael@0 37 * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for
michael@0 38 * the curve whose parameters are encoded in params with base point G.
michael@0 39 */
michael@0 40 SECStatus
michael@0 41 ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2,
michael@0 42 const SECItem *pointP, SECItem *pointQ)
michael@0 43 {
michael@0 44 mp_int Px, Py, Qx, Qy;
michael@0 45 mp_int Gx, Gy, order, irreducible, a, b;
michael@0 46 #if 0 /* currently don't support non-named curves */
michael@0 47 unsigned int irr_arr[5];
michael@0 48 #endif
michael@0 49 ECGroup *group = NULL;
michael@0 50 SECStatus rv = SECFailure;
michael@0 51 mp_err err = MP_OKAY;
michael@0 52 int len;
michael@0 53
michael@0 54 #if EC_DEBUG
michael@0 55 int i;
michael@0 56 char mpstr[256];
michael@0 57
michael@0 58 printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len);
michael@0 59 for (i = 0; i < params->DEREncoding.len; i++)
michael@0 60 printf("%02x:", params->DEREncoding.data[i]);
michael@0 61 printf("\n");
michael@0 62
michael@0 63 if (k1 != NULL) {
michael@0 64 mp_tohex(k1, mpstr);
michael@0 65 printf("ec_points_mul: scalar k1: %s\n", mpstr);
michael@0 66 mp_todecimal(k1, mpstr);
michael@0 67 printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr);
michael@0 68 }
michael@0 69
michael@0 70 if (k2 != NULL) {
michael@0 71 mp_tohex(k2, mpstr);
michael@0 72 printf("ec_points_mul: scalar k2: %s\n", mpstr);
michael@0 73 mp_todecimal(k2, mpstr);
michael@0 74 printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr);
michael@0 75 }
michael@0 76
michael@0 77 if (pointP != NULL) {
michael@0 78 printf("ec_points_mul: pointP [len=%d]:", pointP->len);
michael@0 79 for (i = 0; i < pointP->len; i++)
michael@0 80 printf("%02x:", pointP->data[i]);
michael@0 81 printf("\n");
michael@0 82 }
michael@0 83 #endif
michael@0 84
michael@0 85 /* NOTE: We only support uncompressed points for now */
michael@0 86 len = (params->fieldID.size + 7) >> 3;
michael@0 87 if (pointP != NULL) {
michael@0 88 if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) ||
michael@0 89 (pointP->len != (2 * len + 1))) {
michael@0 90 PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
michael@0 91 return SECFailure;
michael@0 92 };
michael@0 93 }
michael@0 94
michael@0 95 MP_DIGITS(&Px) = 0;
michael@0 96 MP_DIGITS(&Py) = 0;
michael@0 97 MP_DIGITS(&Qx) = 0;
michael@0 98 MP_DIGITS(&Qy) = 0;
michael@0 99 MP_DIGITS(&Gx) = 0;
michael@0 100 MP_DIGITS(&Gy) = 0;
michael@0 101 MP_DIGITS(&order) = 0;
michael@0 102 MP_DIGITS(&irreducible) = 0;
michael@0 103 MP_DIGITS(&a) = 0;
michael@0 104 MP_DIGITS(&b) = 0;
michael@0 105 CHECK_MPI_OK( mp_init(&Px) );
michael@0 106 CHECK_MPI_OK( mp_init(&Py) );
michael@0 107 CHECK_MPI_OK( mp_init(&Qx) );
michael@0 108 CHECK_MPI_OK( mp_init(&Qy) );
michael@0 109 CHECK_MPI_OK( mp_init(&Gx) );
michael@0 110 CHECK_MPI_OK( mp_init(&Gy) );
michael@0 111 CHECK_MPI_OK( mp_init(&order) );
michael@0 112 CHECK_MPI_OK( mp_init(&irreducible) );
michael@0 113 CHECK_MPI_OK( mp_init(&a) );
michael@0 114 CHECK_MPI_OK( mp_init(&b) );
michael@0 115
michael@0 116 if ((k2 != NULL) && (pointP != NULL)) {
michael@0 117 /* Initialize Px and Py */
michael@0 118 CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size) len) );
michael@0 119 CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size) len) );
michael@0 120 }
michael@0 121
michael@0 122 /* construct from named params, if possible */
michael@0 123 if (params->name != ECCurve_noName) {
michael@0 124 group = ECGroup_fromName(params->name);
michael@0 125 }
michael@0 126
michael@0 127 #if 0 /* currently don't support non-named curves */
michael@0 128 if (group == NULL) {
michael@0 129 /* Set up mp_ints containing the curve coefficients */
michael@0 130 CHECK_MPI_OK( mp_read_unsigned_octets(&Gx, params->base.data + 1,
michael@0 131 (mp_size) len) );
michael@0 132 CHECK_MPI_OK( mp_read_unsigned_octets(&Gy, params->base.data + 1 + len,
michael@0 133 (mp_size) len) );
michael@0 134 SECITEM_TO_MPINT( params->order, &order );
michael@0 135 SECITEM_TO_MPINT( params->curve.a, &a );
michael@0 136 SECITEM_TO_MPINT( params->curve.b, &b );
michael@0 137 if (params->fieldID.type == ec_field_GFp) {
michael@0 138 SECITEM_TO_MPINT( params->fieldID.u.prime, &irreducible );
michael@0 139 group = ECGroup_consGFp(&irreducible, &a, &b, &Gx, &Gy, &order, params->cofactor);
michael@0 140 } else {
michael@0 141 SECITEM_TO_MPINT( params->fieldID.u.poly, &irreducible );
michael@0 142 irr_arr[0] = params->fieldID.size;
michael@0 143 irr_arr[1] = params->fieldID.k1;
michael@0 144 irr_arr[2] = params->fieldID.k2;
michael@0 145 irr_arr[3] = params->fieldID.k3;
michael@0 146 irr_arr[4] = 0;
michael@0 147 group = ECGroup_consGF2m(&irreducible, irr_arr, &a, &b, &Gx, &Gy, &order, params->cofactor);
michael@0 148 }
michael@0 149 }
michael@0 150 #endif
michael@0 151 if (group == NULL)
michael@0 152 goto cleanup;
michael@0 153
michael@0 154 if ((k2 != NULL) && (pointP != NULL)) {
michael@0 155 CHECK_MPI_OK( ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy) );
michael@0 156 } else {
michael@0 157 CHECK_MPI_OK( ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy) );
michael@0 158 }
michael@0 159
michael@0 160 /* Construct the SECItem representation of point Q */
michael@0 161 pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED;
michael@0 162 CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1,
michael@0 163 (mp_size) len) );
michael@0 164 CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len,
michael@0 165 (mp_size) len) );
michael@0 166
michael@0 167 rv = SECSuccess;
michael@0 168
michael@0 169 #if EC_DEBUG
michael@0 170 printf("ec_points_mul: pointQ [len=%d]:", pointQ->len);
michael@0 171 for (i = 0; i < pointQ->len; i++)
michael@0 172 printf("%02x:", pointQ->data[i]);
michael@0 173 printf("\n");
michael@0 174 #endif
michael@0 175
michael@0 176 cleanup:
michael@0 177 ECGroup_free(group);
michael@0 178 mp_clear(&Px);
michael@0 179 mp_clear(&Py);
michael@0 180 mp_clear(&Qx);
michael@0 181 mp_clear(&Qy);
michael@0 182 mp_clear(&Gx);
michael@0 183 mp_clear(&Gy);
michael@0 184 mp_clear(&order);
michael@0 185 mp_clear(&irreducible);
michael@0 186 mp_clear(&a);
michael@0 187 mp_clear(&b);
michael@0 188 if (err) {
michael@0 189 MP_TO_SEC_ERROR(err);
michael@0 190 rv = SECFailure;
michael@0 191 }
michael@0 192
michael@0 193 return rv;
michael@0 194 }
michael@0 195 #endif /* NSS_DISABLE_ECC */
michael@0 196
michael@0 197 /* Generates a new EC key pair. The private key is a supplied
michael@0 198 * value and the public key is the result of performing a scalar
michael@0 199 * point multiplication of that value with the curve's base point.
michael@0 200 */
michael@0 201 SECStatus
michael@0 202 ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey,
michael@0 203 const unsigned char *privKeyBytes, int privKeyLen)
michael@0 204 {
michael@0 205 SECStatus rv = SECFailure;
michael@0 206 #ifndef NSS_DISABLE_ECC
michael@0 207 PLArenaPool *arena;
michael@0 208 ECPrivateKey *key;
michael@0 209 mp_int k;
michael@0 210 mp_err err = MP_OKAY;
michael@0 211 int len;
michael@0 212
michael@0 213 #if EC_DEBUG
michael@0 214 printf("ec_NewKey called\n");
michael@0 215 #endif
michael@0 216 MP_DIGITS(&k) = 0;
michael@0 217
michael@0 218 if (!ecParams || !privKey || !privKeyBytes || (privKeyLen < 0)) {
michael@0 219 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 220 return SECFailure;
michael@0 221 }
michael@0 222
michael@0 223 /* Initialize an arena for the EC key. */
michael@0 224 if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)))
michael@0 225 return SECFailure;
michael@0 226
michael@0 227 key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
michael@0 228 if (!key) {
michael@0 229 PORT_FreeArena(arena, PR_TRUE);
michael@0 230 return SECFailure;
michael@0 231 }
michael@0 232
michael@0 233 /* Set the version number (SEC 1 section C.4 says it should be 1) */
michael@0 234 SECITEM_AllocItem(arena, &key->version, 1);
michael@0 235 key->version.data[0] = 1;
michael@0 236
michael@0 237 /* Copy all of the fields from the ECParams argument to the
michael@0 238 * ECParams structure within the private key.
michael@0 239 */
michael@0 240 key->ecParams.arena = arena;
michael@0 241 key->ecParams.type = ecParams->type;
michael@0 242 key->ecParams.fieldID.size = ecParams->fieldID.size;
michael@0 243 key->ecParams.fieldID.type = ecParams->fieldID.type;
michael@0 244 if (ecParams->fieldID.type == ec_field_GFp) {
michael@0 245 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime,
michael@0 246 &ecParams->fieldID.u.prime));
michael@0 247 } else {
michael@0 248 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly,
michael@0 249 &ecParams->fieldID.u.poly));
michael@0 250 }
michael@0 251 key->ecParams.fieldID.k1 = ecParams->fieldID.k1;
michael@0 252 key->ecParams.fieldID.k2 = ecParams->fieldID.k2;
michael@0 253 key->ecParams.fieldID.k3 = ecParams->fieldID.k3;
michael@0 254 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a,
michael@0 255 &ecParams->curve.a));
michael@0 256 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b,
michael@0 257 &ecParams->curve.b));
michael@0 258 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed,
michael@0 259 &ecParams->curve.seed));
michael@0 260 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base,
michael@0 261 &ecParams->base));
michael@0 262 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order,
michael@0 263 &ecParams->order));
michael@0 264 key->ecParams.cofactor = ecParams->cofactor;
michael@0 265 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding,
michael@0 266 &ecParams->DEREncoding));
michael@0 267 key->ecParams.name = ecParams->name;
michael@0 268 CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID,
michael@0 269 &ecParams->curveOID));
michael@0 270
michael@0 271 len = (ecParams->fieldID.size + 7) >> 3;
michael@0 272 SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1);
michael@0 273 len = ecParams->order.len;
michael@0 274 SECITEM_AllocItem(arena, &key->privateValue, len);
michael@0 275
michael@0 276 /* Copy private key */
michael@0 277 if (privKeyLen >= len) {
michael@0 278 memcpy(key->privateValue.data, privKeyBytes, len);
michael@0 279 } else {
michael@0 280 memset(key->privateValue.data, 0, (len - privKeyLen));
michael@0 281 memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen);
michael@0 282 }
michael@0 283
michael@0 284 /* Compute corresponding public key */
michael@0 285 CHECK_MPI_OK( mp_init(&k) );
michael@0 286 CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data,
michael@0 287 (mp_size) len) );
michael@0 288
michael@0 289 rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue));
michael@0 290 if (rv != SECSuccess) goto cleanup;
michael@0 291 *privKey = key;
michael@0 292
michael@0 293 cleanup:
michael@0 294 mp_clear(&k);
michael@0 295 if (rv)
michael@0 296 PORT_FreeArena(arena, PR_TRUE);
michael@0 297
michael@0 298 #if EC_DEBUG
michael@0 299 printf("ec_NewKey returning %s\n",
michael@0 300 (rv == SECSuccess) ? "success" : "failure");
michael@0 301 #endif
michael@0 302 #else
michael@0 303 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 304 #endif /* NSS_DISABLE_ECC */
michael@0 305
michael@0 306 return rv;
michael@0 307
michael@0 308 }
michael@0 309
michael@0 310 /* Generates a new EC key pair. The private key is a supplied
michael@0 311 * random value (in seed) and the public key is the result of
michael@0 312 * performing a scalar point multiplication of that value with
michael@0 313 * the curve's base point.
michael@0 314 */
michael@0 315 SECStatus
michael@0 316 EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey,
michael@0 317 const unsigned char *seed, int seedlen)
michael@0 318 {
michael@0 319 SECStatus rv = SECFailure;
michael@0 320 #ifndef NSS_DISABLE_ECC
michael@0 321 rv = ec_NewKey(ecParams, privKey, seed, seedlen);
michael@0 322 #else
michael@0 323 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 324 #endif /* NSS_DISABLE_ECC */
michael@0 325 return rv;
michael@0 326 }
michael@0 327
michael@0 328 #ifndef NSS_DISABLE_ECC
michael@0 329 /* Generate a random private key using the algorithm A.4.1 of ANSI X9.62,
michael@0 330 * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the
michael@0 331 * random number generator.
michael@0 332 *
michael@0 333 * Parameters
michael@0 334 * - order: a buffer that holds the curve's group order
michael@0 335 * - len: the length in octets of the order buffer
michael@0 336 *
michael@0 337 * Return Value
michael@0 338 * Returns a buffer of len octets that holds the private key. The caller
michael@0 339 * is responsible for freeing the buffer with PORT_ZFree.
michael@0 340 */
michael@0 341 static unsigned char *
michael@0 342 ec_GenerateRandomPrivateKey(const unsigned char *order, int len)
michael@0 343 {
michael@0 344 SECStatus rv = SECSuccess;
michael@0 345 mp_err err;
michael@0 346 unsigned char *privKeyBytes = NULL;
michael@0 347 mp_int privKeyVal, order_1, one;
michael@0 348
michael@0 349 MP_DIGITS(&privKeyVal) = 0;
michael@0 350 MP_DIGITS(&order_1) = 0;
michael@0 351 MP_DIGITS(&one) = 0;
michael@0 352 CHECK_MPI_OK( mp_init(&privKeyVal) );
michael@0 353 CHECK_MPI_OK( mp_init(&order_1) );
michael@0 354 CHECK_MPI_OK( mp_init(&one) );
michael@0 355
michael@0 356 /* Generates 2*len random bytes using the global random bit generator
michael@0 357 * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then
michael@0 358 * reduces modulo the group order.
michael@0 359 */
michael@0 360 if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup;
michael@0 361 CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) );
michael@0 362 CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) );
michael@0 363 CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) );
michael@0 364 CHECK_MPI_OK( mp_set_int(&one, 1) );
michael@0 365 CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) );
michael@0 366 CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) );
michael@0 367 CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
michael@0 368 CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
michael@0 369 memset(privKeyBytes+len, 0, len);
michael@0 370 cleanup:
michael@0 371 mp_clear(&privKeyVal);
michael@0 372 mp_clear(&order_1);
michael@0 373 mp_clear(&one);
michael@0 374 if (err < MP_OKAY) {
michael@0 375 MP_TO_SEC_ERROR(err);
michael@0 376 rv = SECFailure;
michael@0 377 }
michael@0 378 if (rv != SECSuccess && privKeyBytes) {
michael@0 379 PORT_Free(privKeyBytes);
michael@0 380 privKeyBytes = NULL;
michael@0 381 }
michael@0 382 return privKeyBytes;
michael@0 383 }
michael@0 384 #endif /* NSS_DISABLE_ECC */
michael@0 385
michael@0 386 /* Generates a new EC key pair. The private key is a random value and
michael@0 387 * the public key is the result of performing a scalar point multiplication
michael@0 388 * of that value with the curve's base point.
michael@0 389 */
michael@0 390 SECStatus
michael@0 391 EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey)
michael@0 392 {
michael@0 393 SECStatus rv = SECFailure;
michael@0 394 #ifndef NSS_DISABLE_ECC
michael@0 395 int len;
michael@0 396 unsigned char *privKeyBytes = NULL;
michael@0 397
michael@0 398 if (!ecParams) {
michael@0 399 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 400 return SECFailure;
michael@0 401 }
michael@0 402
michael@0 403 len = ecParams->order.len;
michael@0 404 privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len);
michael@0 405 if (privKeyBytes == NULL) goto cleanup;
michael@0 406 /* generate public key */
michael@0 407 CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) );
michael@0 408
michael@0 409 cleanup:
michael@0 410 if (privKeyBytes) {
michael@0 411 PORT_ZFree(privKeyBytes, len);
michael@0 412 }
michael@0 413 #if EC_DEBUG
michael@0 414 printf("EC_NewKey returning %s\n",
michael@0 415 (rv == SECSuccess) ? "success" : "failure");
michael@0 416 #endif
michael@0 417 #else
michael@0 418 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 419 #endif /* NSS_DISABLE_ECC */
michael@0 420
michael@0 421 return rv;
michael@0 422 }
michael@0 423
michael@0 424 /* Validates an EC public key as described in Section 5.2.2 of
michael@0 425 * X9.62. The ECDH primitive when used without the cofactor does
michael@0 426 * not address small subgroup attacks, which may occur when the
michael@0 427 * public key is not valid. These attacks can be prevented by
michael@0 428 * validating the public key before using ECDH.
michael@0 429 */
michael@0 430 SECStatus
michael@0 431 EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue)
michael@0 432 {
michael@0 433 #ifndef NSS_DISABLE_ECC
michael@0 434 mp_int Px, Py;
michael@0 435 ECGroup *group = NULL;
michael@0 436 SECStatus rv = SECFailure;
michael@0 437 mp_err err = MP_OKAY;
michael@0 438 int len;
michael@0 439
michael@0 440 if (!ecParams || !publicValue) {
michael@0 441 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 442 return SECFailure;
michael@0 443 }
michael@0 444
michael@0 445 /* NOTE: We only support uncompressed points for now */
michael@0 446 len = (ecParams->fieldID.size + 7) >> 3;
michael@0 447 if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
michael@0 448 PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
michael@0 449 return SECFailure;
michael@0 450 } else if (publicValue->len != (2 * len + 1)) {
michael@0 451 PORT_SetError(SEC_ERROR_BAD_KEY);
michael@0 452 return SECFailure;
michael@0 453 }
michael@0 454
michael@0 455 MP_DIGITS(&Px) = 0;
michael@0 456 MP_DIGITS(&Py) = 0;
michael@0 457 CHECK_MPI_OK( mp_init(&Px) );
michael@0 458 CHECK_MPI_OK( mp_init(&Py) );
michael@0 459
michael@0 460 /* Initialize Px and Py */
michael@0 461 CHECK_MPI_OK( mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size) len) );
michael@0 462 CHECK_MPI_OK( mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size) len) );
michael@0 463
michael@0 464 /* construct from named params */
michael@0 465 group = ECGroup_fromName(ecParams->name);
michael@0 466 if (group == NULL) {
michael@0 467 /*
michael@0 468 * ECGroup_fromName fails if ecParams->name is not a valid
michael@0 469 * ECCurveName value, or if we run out of memory, or perhaps
michael@0 470 * for other reasons. Unfortunately if ecParams->name is a
michael@0 471 * valid ECCurveName value, we don't know what the right error
michael@0 472 * code should be because ECGroup_fromName doesn't return an
michael@0 473 * error code to the caller. Set err to MP_UNDEF because
michael@0 474 * that's what ECGroup_fromName uses internally.
michael@0 475 */
michael@0 476 if ((ecParams->name <= ECCurve_noName) ||
michael@0 477 (ecParams->name >= ECCurve_pastLastCurve)) {
michael@0 478 err = MP_BADARG;
michael@0 479 } else {
michael@0 480 err = MP_UNDEF;
michael@0 481 }
michael@0 482 goto cleanup;
michael@0 483 }
michael@0 484
michael@0 485 /* validate public point */
michael@0 486 if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) {
michael@0 487 if (err == MP_NO) {
michael@0 488 PORT_SetError(SEC_ERROR_BAD_KEY);
michael@0 489 rv = SECFailure;
michael@0 490 err = MP_OKAY; /* don't change the error code */
michael@0 491 }
michael@0 492 goto cleanup;
michael@0 493 }
michael@0 494
michael@0 495 rv = SECSuccess;
michael@0 496
michael@0 497 cleanup:
michael@0 498 ECGroup_free(group);
michael@0 499 mp_clear(&Px);
michael@0 500 mp_clear(&Py);
michael@0 501 if (err) {
michael@0 502 MP_TO_SEC_ERROR(err);
michael@0 503 rv = SECFailure;
michael@0 504 }
michael@0 505 return rv;
michael@0 506 #else
michael@0 507 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 508 return SECFailure;
michael@0 509 #endif /* NSS_DISABLE_ECC */
michael@0 510 }
michael@0 511
michael@0 512 /*
michael@0 513 ** Performs an ECDH key derivation by computing the scalar point
michael@0 514 ** multiplication of privateValue and publicValue (with or without the
michael@0 515 ** cofactor) and returns the x-coordinate of the resulting elliptic
michael@0 516 ** curve point in derived secret. If successful, derivedSecret->data
michael@0 517 ** is set to the address of the newly allocated buffer containing the
michael@0 518 ** derived secret, and derivedSecret->len is the size of the secret
michael@0 519 ** produced. It is the caller's responsibility to free the allocated
michael@0 520 ** buffer containing the derived secret.
michael@0 521 */
michael@0 522 SECStatus
michael@0 523 ECDH_Derive(SECItem *publicValue,
michael@0 524 ECParams *ecParams,
michael@0 525 SECItem *privateValue,
michael@0 526 PRBool withCofactor,
michael@0 527 SECItem *derivedSecret)
michael@0 528 {
michael@0 529 SECStatus rv = SECFailure;
michael@0 530 #ifndef NSS_DISABLE_ECC
michael@0 531 unsigned int len = 0;
michael@0 532 SECItem pointQ = {siBuffer, NULL, 0};
michael@0 533 mp_int k; /* to hold the private value */
michael@0 534 mp_int cofactor;
michael@0 535 mp_err err = MP_OKAY;
michael@0 536 #if EC_DEBUG
michael@0 537 int i;
michael@0 538 #endif
michael@0 539
michael@0 540 if (!publicValue || !ecParams || !privateValue ||
michael@0 541 !derivedSecret) {
michael@0 542 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 543 return SECFailure;
michael@0 544 }
michael@0 545
michael@0 546 MP_DIGITS(&k) = 0;
michael@0 547 memset(derivedSecret, 0, sizeof *derivedSecret);
michael@0 548 len = (ecParams->fieldID.size + 7) >> 3;
michael@0 549 pointQ.len = 2*len + 1;
michael@0 550 if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup;
michael@0 551
michael@0 552 CHECK_MPI_OK( mp_init(&k) );
michael@0 553 CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data,
michael@0 554 (mp_size) privateValue->len) );
michael@0 555
michael@0 556 if (withCofactor && (ecParams->cofactor != 1)) {
michael@0 557 /* multiply k with the cofactor */
michael@0 558 MP_DIGITS(&cofactor) = 0;
michael@0 559 CHECK_MPI_OK( mp_init(&cofactor) );
michael@0 560 mp_set(&cofactor, ecParams->cofactor);
michael@0 561 CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) );
michael@0 562 }
michael@0 563
michael@0 564 /* Multiply our private key and peer's public point */
michael@0 565 if (ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess)
michael@0 566 goto cleanup;
michael@0 567 if (ec_point_at_infinity(&pointQ)) {
michael@0 568 PORT_SetError(SEC_ERROR_BAD_KEY); /* XXX better error code? */
michael@0 569 goto cleanup;
michael@0 570 }
michael@0 571
michael@0 572 /* Allocate memory for the derived secret and copy
michael@0 573 * the x co-ordinate of pointQ into it.
michael@0 574 */
michael@0 575 SECITEM_AllocItem(NULL, derivedSecret, len);
michael@0 576 memcpy(derivedSecret->data, pointQ.data + 1, len);
michael@0 577
michael@0 578 rv = SECSuccess;
michael@0 579
michael@0 580 #if EC_DEBUG
michael@0 581 printf("derived_secret:\n");
michael@0 582 for (i = 0; i < derivedSecret->len; i++)
michael@0 583 printf("%02x:", derivedSecret->data[i]);
michael@0 584 printf("\n");
michael@0 585 #endif
michael@0 586
michael@0 587 cleanup:
michael@0 588 mp_clear(&k);
michael@0 589
michael@0 590 if (err) {
michael@0 591 MP_TO_SEC_ERROR(err);
michael@0 592 }
michael@0 593
michael@0 594 if (pointQ.data) {
michael@0 595 PORT_ZFree(pointQ.data, 2*len + 1);
michael@0 596 }
michael@0 597 #else
michael@0 598 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 599 #endif /* NSS_DISABLE_ECC */
michael@0 600
michael@0 601 return rv;
michael@0 602 }
michael@0 603
michael@0 604 /* Computes the ECDSA signature (a concatenation of two values r and s)
michael@0 605 * on the digest using the given key and the random value kb (used in
michael@0 606 * computing s).
michael@0 607 */
michael@0 608 SECStatus
michael@0 609 ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature,
michael@0 610 const SECItem *digest, const unsigned char *kb, const int kblen)
michael@0 611 {
michael@0 612 SECStatus rv = SECFailure;
michael@0 613 #ifndef NSS_DISABLE_ECC
michael@0 614 mp_int x1;
michael@0 615 mp_int d, k; /* private key, random integer */
michael@0 616 mp_int r, s; /* tuple (r, s) is the signature */
michael@0 617 mp_int n;
michael@0 618 mp_err err = MP_OKAY;
michael@0 619 ECParams *ecParams = NULL;
michael@0 620 SECItem kGpoint = { siBuffer, NULL, 0};
michael@0 621 int flen = 0; /* length in bytes of the field size */
michael@0 622 unsigned olen; /* length in bytes of the base point order */
michael@0 623 unsigned obits; /* length in bits of the base point order */
michael@0 624
michael@0 625 #if EC_DEBUG
michael@0 626 char mpstr[256];
michael@0 627 #endif
michael@0 628
michael@0 629 /* Initialize MPI integers. */
michael@0 630 /* must happen before the first potential call to cleanup */
michael@0 631 MP_DIGITS(&x1) = 0;
michael@0 632 MP_DIGITS(&d) = 0;
michael@0 633 MP_DIGITS(&k) = 0;
michael@0 634 MP_DIGITS(&r) = 0;
michael@0 635 MP_DIGITS(&s) = 0;
michael@0 636 MP_DIGITS(&n) = 0;
michael@0 637
michael@0 638 /* Check args */
michael@0 639 if (!key || !signature || !digest || !kb || (kblen < 0)) {
michael@0 640 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 641 goto cleanup;
michael@0 642 }
michael@0 643
michael@0 644 ecParams = &(key->ecParams);
michael@0 645 flen = (ecParams->fieldID.size + 7) >> 3;
michael@0 646 olen = ecParams->order.len;
michael@0 647 if (signature->data == NULL) {
michael@0 648 /* a call to get the signature length only */
michael@0 649 goto finish;
michael@0 650 }
michael@0 651 if (signature->len < 2*olen) {
michael@0 652 PORT_SetError(SEC_ERROR_OUTPUT_LEN);
michael@0 653 goto cleanup;
michael@0 654 }
michael@0 655
michael@0 656
michael@0 657 CHECK_MPI_OK( mp_init(&x1) );
michael@0 658 CHECK_MPI_OK( mp_init(&d) );
michael@0 659 CHECK_MPI_OK( mp_init(&k) );
michael@0 660 CHECK_MPI_OK( mp_init(&r) );
michael@0 661 CHECK_MPI_OK( mp_init(&s) );
michael@0 662 CHECK_MPI_OK( mp_init(&n) );
michael@0 663
michael@0 664 SECITEM_TO_MPINT( ecParams->order, &n );
michael@0 665 SECITEM_TO_MPINT( key->privateValue, &d );
michael@0 666
michael@0 667 CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) );
michael@0 668 /* Make sure k is in the interval [1, n-1] */
michael@0 669 if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) {
michael@0 670 #if EC_DEBUG
michael@0 671 printf("k is outside [1, n-1]\n");
michael@0 672 mp_tohex(&k, mpstr);
michael@0 673 printf("k : %s \n", mpstr);
michael@0 674 mp_tohex(&n, mpstr);
michael@0 675 printf("n : %s \n", mpstr);
michael@0 676 #endif
michael@0 677 PORT_SetError(SEC_ERROR_NEED_RANDOM);
michael@0 678 goto cleanup;
michael@0 679 }
michael@0 680
michael@0 681 /*
michael@0 682 ** We do not want timing information to leak the length of k,
michael@0 683 ** so we compute k*G using an equivalent scalar of fixed
michael@0 684 ** bit-length.
michael@0 685 ** Fix based on patch for ECDSA timing attack in the paper
michael@0 686 ** by Billy Bob Brumley and Nicola Tuveri at
michael@0 687 ** http://eprint.iacr.org/2011/232
michael@0 688 **
michael@0 689 ** How do we convert k to a value of a fixed bit-length?
michael@0 690 ** k starts off as an integer satisfying 0 <= k < n. Hence,
michael@0 691 ** n <= k+n < 2n, which means k+n has either the same number
michael@0 692 ** of bits as n or one more bit than n. If k+n has the same
michael@0 693 ** number of bits as n, the second addition ensures that the
michael@0 694 ** final value has exactly one more bit than n. Thus, we
michael@0 695 ** always end up with a value that exactly one more bit than n.
michael@0 696 */
michael@0 697 CHECK_MPI_OK( mp_add(&k, &n, &k) );
michael@0 698 if (mpl_significant_bits(&k) <= mpl_significant_bits(&n)) {
michael@0 699 CHECK_MPI_OK( mp_add(&k, &n, &k) );
michael@0 700 }
michael@0 701
michael@0 702 /*
michael@0 703 ** ANSI X9.62, Section 5.3.2, Step 2
michael@0 704 **
michael@0 705 ** Compute kG
michael@0 706 */
michael@0 707 kGpoint.len = 2*flen + 1;
michael@0 708 kGpoint.data = PORT_Alloc(2*flen + 1);
michael@0 709 if ((kGpoint.data == NULL) ||
michael@0 710 (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint)
michael@0 711 != SECSuccess))
michael@0 712 goto cleanup;
michael@0 713
michael@0 714 /*
michael@0 715 ** ANSI X9.62, Section 5.3.3, Step 1
michael@0 716 **
michael@0 717 ** Extract the x co-ordinate of kG into x1
michael@0 718 */
michael@0 719 CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1,
michael@0 720 (mp_size) flen) );
michael@0 721
michael@0 722 /*
michael@0 723 ** ANSI X9.62, Section 5.3.3, Step 2
michael@0 724 **
michael@0 725 ** r = x1 mod n NOTE: n is the order of the curve
michael@0 726 */
michael@0 727 CHECK_MPI_OK( mp_mod(&x1, &n, &r) );
michael@0 728
michael@0 729 /*
michael@0 730 ** ANSI X9.62, Section 5.3.3, Step 3
michael@0 731 **
michael@0 732 ** verify r != 0
michael@0 733 */
michael@0 734 if (mp_cmp_z(&r) == 0) {
michael@0 735 PORT_SetError(SEC_ERROR_NEED_RANDOM);
michael@0 736 goto cleanup;
michael@0 737 }
michael@0 738
michael@0 739 /*
michael@0 740 ** ANSI X9.62, Section 5.3.3, Step 4
michael@0 741 **
michael@0 742 ** s = (k**-1 * (HASH(M) + d*r)) mod n
michael@0 743 */
michael@0 744 SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */
michael@0 745
michael@0 746 /* In the definition of EC signing, digests are truncated
michael@0 747 * to the length of n in bits.
michael@0 748 * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
michael@0 749 CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) );
michael@0 750 if (digest->len*8 > obits) {
michael@0 751 mpl_rsh(&s,&s,digest->len*8 - obits);
michael@0 752 }
michael@0 753
michael@0 754 #if EC_DEBUG
michael@0 755 mp_todecimal(&n, mpstr);
michael@0 756 printf("n : %s (dec)\n", mpstr);
michael@0 757 mp_todecimal(&d, mpstr);
michael@0 758 printf("d : %s (dec)\n", mpstr);
michael@0 759 mp_tohex(&x1, mpstr);
michael@0 760 printf("x1: %s\n", mpstr);
michael@0 761 mp_todecimal(&s, mpstr);
michael@0 762 printf("digest: %s (decimal)\n", mpstr);
michael@0 763 mp_todecimal(&r, mpstr);
michael@0 764 printf("r : %s (dec)\n", mpstr);
michael@0 765 mp_tohex(&r, mpstr);
michael@0 766 printf("r : %s\n", mpstr);
michael@0 767 #endif
michael@0 768
michael@0 769 CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */
michael@0 770 CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */
michael@0 771 CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */
michael@0 772 CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */
michael@0 773
michael@0 774 #if EC_DEBUG
michael@0 775 mp_todecimal(&s, mpstr);
michael@0 776 printf("s : %s (dec)\n", mpstr);
michael@0 777 mp_tohex(&s, mpstr);
michael@0 778 printf("s : %s\n", mpstr);
michael@0 779 #endif
michael@0 780
michael@0 781 /*
michael@0 782 ** ANSI X9.62, Section 5.3.3, Step 5
michael@0 783 **
michael@0 784 ** verify s != 0
michael@0 785 */
michael@0 786 if (mp_cmp_z(&s) == 0) {
michael@0 787 PORT_SetError(SEC_ERROR_NEED_RANDOM);
michael@0 788 goto cleanup;
michael@0 789 }
michael@0 790
michael@0 791 /*
michael@0 792 **
michael@0 793 ** Signature is tuple (r, s)
michael@0 794 */
michael@0 795 CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) );
michael@0 796 CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) );
michael@0 797 finish:
michael@0 798 signature->len = 2*olen;
michael@0 799
michael@0 800 rv = SECSuccess;
michael@0 801 err = MP_OKAY;
michael@0 802 cleanup:
michael@0 803 mp_clear(&x1);
michael@0 804 mp_clear(&d);
michael@0 805 mp_clear(&k);
michael@0 806 mp_clear(&r);
michael@0 807 mp_clear(&s);
michael@0 808 mp_clear(&n);
michael@0 809
michael@0 810 if (kGpoint.data) {
michael@0 811 PORT_ZFree(kGpoint.data, 2*flen + 1);
michael@0 812 }
michael@0 813
michael@0 814 if (err) {
michael@0 815 MP_TO_SEC_ERROR(err);
michael@0 816 rv = SECFailure;
michael@0 817 }
michael@0 818
michael@0 819 #if EC_DEBUG
michael@0 820 printf("ECDSA signing with seed %s\n",
michael@0 821 (rv == SECSuccess) ? "succeeded" : "failed");
michael@0 822 #endif
michael@0 823 #else
michael@0 824 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 825 #endif /* NSS_DISABLE_ECC */
michael@0 826
michael@0 827 return rv;
michael@0 828 }
michael@0 829
michael@0 830 /*
michael@0 831 ** Computes the ECDSA signature on the digest using the given key
michael@0 832 ** and a random seed.
michael@0 833 */
michael@0 834 SECStatus
michael@0 835 ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest)
michael@0 836 {
michael@0 837 SECStatus rv = SECFailure;
michael@0 838 #ifndef NSS_DISABLE_ECC
michael@0 839 int len;
michael@0 840 unsigned char *kBytes= NULL;
michael@0 841
michael@0 842 if (!key) {
michael@0 843 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 844 return SECFailure;
michael@0 845 }
michael@0 846
michael@0 847 /* Generate random value k */
michael@0 848 len = key->ecParams.order.len;
michael@0 849 kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len);
michael@0 850 if (kBytes == NULL) goto cleanup;
michael@0 851
michael@0 852 /* Generate ECDSA signature with the specified k value */
michael@0 853 rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len);
michael@0 854
michael@0 855 cleanup:
michael@0 856 if (kBytes) {
michael@0 857 PORT_ZFree(kBytes, len);
michael@0 858 }
michael@0 859
michael@0 860 #if EC_DEBUG
michael@0 861 printf("ECDSA signing %s\n",
michael@0 862 (rv == SECSuccess) ? "succeeded" : "failed");
michael@0 863 #endif
michael@0 864 #else
michael@0 865 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 866 #endif /* NSS_DISABLE_ECC */
michael@0 867
michael@0 868 return rv;
michael@0 869 }
michael@0 870
michael@0 871 /*
michael@0 872 ** Checks the signature on the given digest using the key provided.
michael@0 873 **
michael@0 874 ** The key argument must represent a valid EC public key (a point on
michael@0 875 ** the relevant curve). If it is not a valid point, then the behavior
michael@0 876 ** of this function is undefined. In cases where a public key might
michael@0 877 ** not be valid, use EC_ValidatePublicKey to check.
michael@0 878 */
michael@0 879 SECStatus
michael@0 880 ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature,
michael@0 881 const SECItem *digest)
michael@0 882 {
michael@0 883 SECStatus rv = SECFailure;
michael@0 884 #ifndef NSS_DISABLE_ECC
michael@0 885 mp_int r_, s_; /* tuple (r', s') is received signature) */
michael@0 886 mp_int c, u1, u2, v; /* intermediate values used in verification */
michael@0 887 mp_int x1;
michael@0 888 mp_int n;
michael@0 889 mp_err err = MP_OKAY;
michael@0 890 ECParams *ecParams = NULL;
michael@0 891 SECItem pointC = { siBuffer, NULL, 0 };
michael@0 892 int slen; /* length in bytes of a half signature (r or s) */
michael@0 893 int flen; /* length in bytes of the field size */
michael@0 894 unsigned olen; /* length in bytes of the base point order */
michael@0 895 unsigned obits; /* length in bits of the base point order */
michael@0 896
michael@0 897 #if EC_DEBUG
michael@0 898 char mpstr[256];
michael@0 899 printf("ECDSA verification called\n");
michael@0 900 #endif
michael@0 901
michael@0 902 /* Initialize MPI integers. */
michael@0 903 /* must happen before the first potential call to cleanup */
michael@0 904 MP_DIGITS(&r_) = 0;
michael@0 905 MP_DIGITS(&s_) = 0;
michael@0 906 MP_DIGITS(&c) = 0;
michael@0 907 MP_DIGITS(&u1) = 0;
michael@0 908 MP_DIGITS(&u2) = 0;
michael@0 909 MP_DIGITS(&x1) = 0;
michael@0 910 MP_DIGITS(&v) = 0;
michael@0 911 MP_DIGITS(&n) = 0;
michael@0 912
michael@0 913 /* Check args */
michael@0 914 if (!key || !signature || !digest) {
michael@0 915 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 916 goto cleanup;
michael@0 917 }
michael@0 918
michael@0 919 ecParams = &(key->ecParams);
michael@0 920 flen = (ecParams->fieldID.size + 7) >> 3;
michael@0 921 olen = ecParams->order.len;
michael@0 922 if (signature->len == 0 || signature->len%2 != 0 ||
michael@0 923 signature->len > 2*olen) {
michael@0 924 PORT_SetError(SEC_ERROR_INPUT_LEN);
michael@0 925 goto cleanup;
michael@0 926 }
michael@0 927 slen = signature->len/2;
michael@0 928
michael@0 929 SECITEM_AllocItem(NULL, &pointC, 2*flen + 1);
michael@0 930 if (pointC.data == NULL)
michael@0 931 goto cleanup;
michael@0 932
michael@0 933 CHECK_MPI_OK( mp_init(&r_) );
michael@0 934 CHECK_MPI_OK( mp_init(&s_) );
michael@0 935 CHECK_MPI_OK( mp_init(&c) );
michael@0 936 CHECK_MPI_OK( mp_init(&u1) );
michael@0 937 CHECK_MPI_OK( mp_init(&u2) );
michael@0 938 CHECK_MPI_OK( mp_init(&x1) );
michael@0 939 CHECK_MPI_OK( mp_init(&v) );
michael@0 940 CHECK_MPI_OK( mp_init(&n) );
michael@0 941
michael@0 942 /*
michael@0 943 ** Convert received signature (r', s') into MPI integers.
michael@0 944 */
michael@0 945 CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) );
michael@0 946 CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) );
michael@0 947
michael@0 948 /*
michael@0 949 ** ANSI X9.62, Section 5.4.2, Steps 1 and 2
michael@0 950 **
michael@0 951 ** Verify that 0 < r' < n and 0 < s' < n
michael@0 952 */
michael@0 953 SECITEM_TO_MPINT(ecParams->order, &n);
michael@0 954 if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 ||
michael@0 955 mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) {
michael@0 956 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 957 goto cleanup; /* will return rv == SECFailure */
michael@0 958 }
michael@0 959
michael@0 960 /*
michael@0 961 ** ANSI X9.62, Section 5.4.2, Step 3
michael@0 962 **
michael@0 963 ** c = (s')**-1 mod n
michael@0 964 */
michael@0 965 CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */
michael@0 966
michael@0 967 /*
michael@0 968 ** ANSI X9.62, Section 5.4.2, Step 4
michael@0 969 **
michael@0 970 ** u1 = ((HASH(M')) * c) mod n
michael@0 971 */
michael@0 972 SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */
michael@0 973
michael@0 974 /* In the definition of EC signing, digests are truncated
michael@0 975 * to the length of n in bits.
michael@0 976 * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/
michael@0 977 CHECK_MPI_OK( (obits = mpl_significant_bits(&n)) );
michael@0 978 if (digest->len*8 > obits) { /* u1 = HASH(M') */
michael@0 979 mpl_rsh(&u1,&u1,digest->len*8 - obits);
michael@0 980 }
michael@0 981
michael@0 982 #if EC_DEBUG
michael@0 983 mp_todecimal(&r_, mpstr);
michael@0 984 printf("r_: %s (dec)\n", mpstr);
michael@0 985 mp_todecimal(&s_, mpstr);
michael@0 986 printf("s_: %s (dec)\n", mpstr);
michael@0 987 mp_todecimal(&c, mpstr);
michael@0 988 printf("c : %s (dec)\n", mpstr);
michael@0 989 mp_todecimal(&u1, mpstr);
michael@0 990 printf("digest: %s (dec)\n", mpstr);
michael@0 991 #endif
michael@0 992
michael@0 993 CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */
michael@0 994
michael@0 995 /*
michael@0 996 ** ANSI X9.62, Section 5.4.2, Step 4
michael@0 997 **
michael@0 998 ** u2 = ((r') * c) mod n
michael@0 999 */
michael@0 1000 CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) );
michael@0 1001
michael@0 1002 /*
michael@0 1003 ** ANSI X9.62, Section 5.4.3, Step 1
michael@0 1004 **
michael@0 1005 ** Compute u1*G + u2*Q
michael@0 1006 ** Here, A = u1.G B = u2.Q and C = A + B
michael@0 1007 ** If the result, C, is the point at infinity, reject the signature
michael@0 1008 */
michael@0 1009 if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC)
michael@0 1010 != SECSuccess) {
michael@0 1011 rv = SECFailure;
michael@0 1012 goto cleanup;
michael@0 1013 }
michael@0 1014 if (ec_point_at_infinity(&pointC)) {
michael@0 1015 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1016 rv = SECFailure;
michael@0 1017 goto cleanup;
michael@0 1018 }
michael@0 1019
michael@0 1020 CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) );
michael@0 1021
michael@0 1022 /*
michael@0 1023 ** ANSI X9.62, Section 5.4.4, Step 2
michael@0 1024 **
michael@0 1025 ** v = x1 mod n
michael@0 1026 */
michael@0 1027 CHECK_MPI_OK( mp_mod(&x1, &n, &v) );
michael@0 1028
michael@0 1029 #if EC_DEBUG
michael@0 1030 mp_todecimal(&r_, mpstr);
michael@0 1031 printf("r_: %s (dec)\n", mpstr);
michael@0 1032 mp_todecimal(&v, mpstr);
michael@0 1033 printf("v : %s (dec)\n", mpstr);
michael@0 1034 #endif
michael@0 1035
michael@0 1036 /*
michael@0 1037 ** ANSI X9.62, Section 5.4.4, Step 3
michael@0 1038 **
michael@0 1039 ** Verification: v == r'
michael@0 1040 */
michael@0 1041 if (mp_cmp(&v, &r_)) {
michael@0 1042 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
michael@0 1043 rv = SECFailure; /* Signature failed to verify. */
michael@0 1044 } else {
michael@0 1045 rv = SECSuccess; /* Signature verified. */
michael@0 1046 }
michael@0 1047
michael@0 1048 #if EC_DEBUG
michael@0 1049 mp_todecimal(&u1, mpstr);
michael@0 1050 printf("u1: %s (dec)\n", mpstr);
michael@0 1051 mp_todecimal(&u2, mpstr);
michael@0 1052 printf("u2: %s (dec)\n", mpstr);
michael@0 1053 mp_tohex(&x1, mpstr);
michael@0 1054 printf("x1: %s\n", mpstr);
michael@0 1055 mp_todecimal(&v, mpstr);
michael@0 1056 printf("v : %s (dec)\n", mpstr);
michael@0 1057 #endif
michael@0 1058
michael@0 1059 cleanup:
michael@0 1060 mp_clear(&r_);
michael@0 1061 mp_clear(&s_);
michael@0 1062 mp_clear(&c);
michael@0 1063 mp_clear(&u1);
michael@0 1064 mp_clear(&u2);
michael@0 1065 mp_clear(&x1);
michael@0 1066 mp_clear(&v);
michael@0 1067 mp_clear(&n);
michael@0 1068
michael@0 1069 if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
michael@0 1070 if (err) {
michael@0 1071 MP_TO_SEC_ERROR(err);
michael@0 1072 rv = SECFailure;
michael@0 1073 }
michael@0 1074
michael@0 1075 #if EC_DEBUG
michael@0 1076 printf("ECDSA verification %s\n",
michael@0 1077 (rv == SECSuccess) ? "succeeded" : "failed");
michael@0 1078 #endif
michael@0 1079 #else
michael@0 1080 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
michael@0 1081 #endif /* NSS_DISABLE_ECC */
michael@0 1082
michael@0 1083 return rv;
michael@0 1084 }
michael@0 1085

mercurial