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