Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #ifdef FREEBL_NO_DEPEND |
6 | | #include "stubs.h" |
7 | | #endif |
8 | | |
9 | | #include "blapi.h" |
10 | | #include "blapii.h" |
11 | | #include "prerr.h" |
12 | | #include "secerr.h" |
13 | | #include "secmpi.h" |
14 | | #include "secitem.h" |
15 | | #include "mplogic.h" |
16 | | #include "ec.h" |
17 | | #include "ecl.h" |
18 | | #include "verified/Hacl_P384.h" |
19 | | #include "verified/Hacl_P521.h" |
20 | | #include "secport.h" |
21 | | #include "verified/Hacl_Ed25519.h" |
22 | | |
23 | | #define EC_DOUBLECHECK PR_FALSE |
24 | | |
25 | | SECStatus |
26 | | ec_ED25519_pt_validate(const SECItem *px) |
27 | 0 | { |
28 | 0 | if (!px || !px->data || px->len != Ed25519_PUBLIC_KEYLEN) { |
29 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
30 | 0 | return SECFailure; |
31 | 0 | } |
32 | 0 | return SECSuccess; |
33 | 0 | } |
34 | | |
35 | | SECStatus |
36 | | ec_ED25519_scalar_validate(const SECItem *scalar) |
37 | 0 | { |
38 | 0 | if (!scalar || !scalar->data || scalar->len != Ed25519_PRIVATE_KEYLEN) { |
39 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
40 | 0 | return SECFailure; |
41 | 0 | } |
42 | | |
43 | 0 | return SECSuccess; |
44 | 0 | } |
45 | | |
46 | | static const ECMethod kMethods[] = { |
47 | | { ECCurve25519, |
48 | | ec_Curve25519_pt_mul, |
49 | | ec_Curve25519_pt_validate, |
50 | | ec_Curve25519_scalar_validate, |
51 | | NULL, |
52 | | NULL }, |
53 | | { |
54 | | ECCurve_NIST_P256, |
55 | | ec_secp256r1_pt_mul, |
56 | | ec_secp256r1_pt_validate, |
57 | | ec_secp256r1_scalar_validate, |
58 | | ec_secp256r1_sign_digest, |
59 | | ec_secp256r1_verify_digest, |
60 | | }, |
61 | | { |
62 | | ECCurve_NIST_P384, |
63 | | ec_secp384r1_pt_mul, |
64 | | ec_secp384r1_pt_validate, |
65 | | ec_secp384r1_scalar_validate, |
66 | | ec_secp384r1_sign_digest, |
67 | | ec_secp384r1_verify_digest, |
68 | | }, |
69 | | { |
70 | | ECCurve_NIST_P521, |
71 | | ec_secp521r1_pt_mul, |
72 | | ec_secp521r1_pt_validate, |
73 | | ec_secp521r1_scalar_validate, |
74 | | ec_secp521r1_sign_digest, |
75 | | ec_secp521r1_verify_digest, |
76 | | }, |
77 | | { ECCurve_Ed25519, |
78 | | NULL, |
79 | | ec_ED25519_pt_validate, |
80 | | ec_ED25519_scalar_validate, |
81 | | NULL, |
82 | | NULL }, |
83 | | }; |
84 | | |
85 | | static const ECMethod * |
86 | | ec_get_method_from_name(ECCurveName name) |
87 | 406k | { |
88 | 406k | unsigned long i; |
89 | 782k | for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); ++i) { |
90 | 782k | if (kMethods[i].name == name) { |
91 | 406k | return &kMethods[i]; |
92 | 406k | } |
93 | 782k | } |
94 | 0 | return NULL; |
95 | 406k | } |
96 | | |
97 | | /* Generates a new EC key pair. The private key is a supplied |
98 | | * value and the public key is the result of performing a scalar |
99 | | * point multiplication of that value with the curve's base point. |
100 | | */ |
101 | | SECStatus |
102 | | ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, |
103 | | const unsigned char *privKeyBytes, int privKeyLen) |
104 | 89.7k | { |
105 | 89.7k | SECStatus rv = SECFailure; |
106 | 89.7k | PLArenaPool *arena; |
107 | 89.7k | ECPrivateKey *key; |
108 | 89.7k | int len; |
109 | | |
110 | 89.7k | if (!ecParams || ecParams->name == ECCurve_noName || |
111 | 89.7k | !privKey || !privKeyBytes || privKeyLen <= 0) { |
112 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
113 | 0 | return SECFailure; |
114 | 0 | } |
115 | | |
116 | 89.7k | if (ecParams->fieldID.type != ec_field_plain) { |
117 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
118 | 0 | return SECFailure; |
119 | 0 | } |
120 | | |
121 | | /* Initialize an arena for the EC key. */ |
122 | 89.7k | if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) |
123 | 0 | return SECFailure; |
124 | | |
125 | 89.7k | key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey)); |
126 | 89.7k | if (!key) { |
127 | 0 | goto cleanup; |
128 | 0 | } |
129 | | |
130 | | /* Set the version number (SEC 1 section C.4 says it should be 1) */ |
131 | 89.7k | SECITEM_AllocItem(arena, &key->version, 1); |
132 | 89.7k | key->version.data[0] = 1; |
133 | | |
134 | | /* Copy all of the fields from the ECParams argument to the |
135 | | * ECParams structure within the private key. |
136 | | */ |
137 | 89.7k | key->ecParams.arena = arena; |
138 | 89.7k | key->ecParams.type = ecParams->type; |
139 | 89.7k | key->ecParams.fieldID.size = ecParams->fieldID.size; |
140 | 89.7k | key->ecParams.fieldID.type = ecParams->fieldID.type; |
141 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime, |
142 | 89.7k | &ecParams->fieldID.u.prime)); |
143 | 89.7k | key->ecParams.fieldID.k1 = ecParams->fieldID.k1; |
144 | 89.7k | key->ecParams.fieldID.k2 = ecParams->fieldID.k2; |
145 | 89.7k | key->ecParams.fieldID.k3 = ecParams->fieldID.k3; |
146 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a, |
147 | 89.7k | &ecParams->curve.a)); |
148 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b, |
149 | 89.7k | &ecParams->curve.b)); |
150 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed, |
151 | 89.7k | &ecParams->curve.seed)); |
152 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base, |
153 | 89.7k | &ecParams->base)); |
154 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order, |
155 | 89.7k | &ecParams->order)); |
156 | 89.7k | key->ecParams.cofactor = ecParams->cofactor; |
157 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding, |
158 | 89.7k | &ecParams->DEREncoding)); |
159 | 89.7k | key->ecParams.name = ecParams->name; |
160 | 89.7k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID, |
161 | 89.7k | &ecParams->curveOID)); |
162 | | |
163 | 89.7k | SECITEM_AllocItem(arena, &key->publicValue, EC_GetPointSize(ecParams)); |
164 | 89.7k | len = ecParams->order.len; |
165 | 89.7k | SECITEM_AllocItem(arena, &key->privateValue, len); |
166 | | |
167 | | /* Copy private key */ |
168 | 89.7k | if (privKeyLen >= len) { |
169 | 89.7k | memcpy(key->privateValue.data, privKeyBytes, len); |
170 | 89.7k | } else { |
171 | 0 | memset(key->privateValue.data, 0, (len - privKeyLen)); |
172 | 0 | memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen); |
173 | 0 | } |
174 | | |
175 | | /* Compute corresponding public key */ |
176 | | |
177 | | /* Use curve specific code for point multiplication */ |
178 | 89.7k | if (ecParams->name == ECCurve_Ed25519) { |
179 | 0 | CHECK_SEC_OK(ED_DerivePublicKey(&key->privateValue, &key->publicValue)); |
180 | 89.7k | } else { |
181 | 89.7k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
182 | 89.7k | if (method == NULL || method->pt_mul == NULL) { |
183 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
184 | 0 | rv = SECFailure; |
185 | 0 | goto cleanup; |
186 | 0 | } |
187 | 89.7k | CHECK_SEC_OK(method->pt_mul(&key->publicValue, &key->privateValue, NULL)); |
188 | 89.7k | } |
189 | | |
190 | 89.3k | NSS_DECLASSIFY(key->publicValue.data, key->publicValue.len); /* Declassifying public key to avoid false positive */ |
191 | 89.3k | *privKey = key; |
192 | 89.3k | return SECSuccess; |
193 | | |
194 | 398 | cleanup: |
195 | 398 | PORT_FreeArena(arena, PR_TRUE); |
196 | 398 | return rv; |
197 | 89.7k | } |
198 | | |
199 | | /* Generates a new EC key pair. The private key is a supplied |
200 | | * random value (in seed) and the public key is the result of |
201 | | * performing a scalar point multiplication of that value with |
202 | | * the curve's base point. |
203 | | */ |
204 | | SECStatus |
205 | | EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, |
206 | | const unsigned char *seed, int seedlen) |
207 | 9.79k | { |
208 | 9.79k | return ec_NewKey(ecParams, privKey, seed, seedlen); |
209 | 9.79k | } |
210 | | |
211 | | /* Generate a random private key using the algorithm A.4.1 or A.4.2 of ANSI X9.62, |
212 | | * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the |
213 | | * random number generator. |
214 | | */ |
215 | | |
216 | | SECStatus |
217 | | ec_GenerateRandomPrivateKey(ECParams *ecParams, SECItem *privKey) |
218 | 89.4k | { |
219 | 89.4k | SECStatus rv = SECFailure; |
220 | | |
221 | 89.4k | unsigned int len = EC_GetScalarSize(ecParams); |
222 | | |
223 | 89.4k | if (privKey->len != len || privKey->data == NULL) { |
224 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
225 | 0 | return SECFailure; |
226 | 0 | } |
227 | | |
228 | 89.4k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
229 | 89.4k | if (method == NULL || method->scalar_validate == NULL) { |
230 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
231 | 0 | return SECFailure; |
232 | 0 | } |
233 | | |
234 | 89.4k | uint8_t leading_coeff_mask; |
235 | 89.4k | switch (ecParams->name) { |
236 | 0 | case ECCurve_Ed25519: |
237 | 20.6k | case ECCurve25519: |
238 | 80.3k | case ECCurve_NIST_P256: |
239 | 89.0k | case ECCurve_NIST_P384: |
240 | 89.0k | leading_coeff_mask = 0xff; |
241 | 89.0k | break; |
242 | 327 | case ECCurve_NIST_P521: |
243 | 327 | leading_coeff_mask = 0x01; |
244 | 327 | break; |
245 | 0 | default: |
246 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
247 | 0 | return SECFailure; |
248 | 89.4k | } |
249 | | |
250 | | /* The rejection sampling method from FIPS 186-5 A.4.2 */ |
251 | 89.4k | int count = 100; |
252 | 89.4k | do { |
253 | 89.4k | rv = RNG_GenerateGlobalRandomBytes(privKey->data, len); |
254 | 89.4k | if (rv != SECSuccess) { |
255 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
256 | 0 | return SECFailure; |
257 | 0 | } |
258 | 89.4k | privKey->data[0] &= leading_coeff_mask; |
259 | 89.4k | NSS_CLASSIFY(privKey->data, privKey->len); |
260 | 89.4k | rv = method->scalar_validate(privKey); |
261 | 89.4k | } while (rv != SECSuccess && --count > 0); |
262 | | |
263 | 89.4k | if (rv != SECSuccess) { // implies count == 0 |
264 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
265 | 0 | } |
266 | | |
267 | 89.4k | return rv; |
268 | 89.4k | } |
269 | | |
270 | | /* Generates a new EC key pair. The private key is a random value and |
271 | | * the public key is the result of performing a scalar point multiplication |
272 | | * of that value with the curve's base point. |
273 | | */ |
274 | | SECStatus |
275 | | EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey) |
276 | 79.9k | { |
277 | 79.9k | SECStatus rv = SECFailure; |
278 | 79.9k | SECItem privKeyRand = { siBuffer, NULL, 0 }; |
279 | | |
280 | 79.9k | if (!ecParams || ecParams->name == ECCurve_noName || !privKey) { |
281 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
282 | 0 | return SECFailure; |
283 | 0 | } |
284 | | |
285 | 79.9k | SECITEM_AllocItem(NULL, &privKeyRand, EC_GetScalarSize(ecParams)); |
286 | 79.9k | if (privKeyRand.data == NULL) { |
287 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
288 | 0 | rv = SECFailure; |
289 | 0 | goto cleanup; |
290 | 0 | } |
291 | 79.9k | rv = ec_GenerateRandomPrivateKey(ecParams, &privKeyRand); |
292 | 79.9k | if (rv != SECSuccess || privKeyRand.data == NULL) { |
293 | 0 | goto cleanup; |
294 | 0 | } |
295 | | /* generate public key */ |
296 | 79.9k | CHECK_SEC_OK(ec_NewKey(ecParams, privKey, privKeyRand.data, privKeyRand.len)); |
297 | | |
298 | 79.9k | cleanup: |
299 | 79.9k | if (privKeyRand.data) { |
300 | 79.9k | SECITEM_ZfreeItem(&privKeyRand, PR_FALSE); |
301 | 79.9k | } |
302 | | #if EC_DEBUG |
303 | | printf("EC_NewKey returning %s\n", |
304 | | (rv == SECSuccess) ? "success" : "failure"); |
305 | | #endif |
306 | | |
307 | 79.9k | return rv; |
308 | 79.9k | } |
309 | | |
310 | | /* Validates an EC public key as described in Section 5.2.2 of |
311 | | * X9.62. The ECDH primitive when used without the cofactor does |
312 | | * not address small subgroup attacks, which may occur when the |
313 | | * public key is not valid. These attacks can be prevented by |
314 | | * validating the public key before using ECDH. |
315 | | */ |
316 | | SECStatus |
317 | | EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue) |
318 | 149k | { |
319 | 149k | if (!ecParams || ecParams->name == ECCurve_noName || |
320 | 149k | !publicValue || !publicValue->len) { |
321 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
322 | 0 | return SECFailure; |
323 | 0 | } |
324 | | |
325 | | /* Uses curve specific code for point validation. */ |
326 | 149k | if (ecParams->fieldID.type != ec_field_plain) { |
327 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
328 | 0 | return SECFailure; |
329 | 0 | } |
330 | | |
331 | 149k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
332 | 149k | if (method == NULL || method->pt_validate == NULL) { |
333 | | /* unknown curve */ |
334 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
335 | 0 | return SECFailure; |
336 | 0 | } |
337 | | |
338 | 149k | SECStatus rv = method->pt_validate(publicValue); |
339 | 149k | if (rv != SECSuccess) { |
340 | 1.50k | PORT_SetError(SEC_ERROR_BAD_KEY); |
341 | 1.50k | } |
342 | 149k | return rv; |
343 | 149k | } |
344 | | |
345 | | /* |
346 | | ** Performs an ECDH key derivation by computing the scalar point |
347 | | ** multiplication of privateValue and publicValue (with or without the |
348 | | ** cofactor) and returns the x-coordinate of the resulting elliptic |
349 | | ** curve point in derived secret. If successful, derivedSecret->data |
350 | | ** is set to the address of the newly allocated buffer containing the |
351 | | ** derived secret, and derivedSecret->len is the size of the secret |
352 | | ** produced. It is the caller's responsibility to free the allocated |
353 | | ** buffer containing the derived secret. |
354 | | */ |
355 | | SECStatus |
356 | | ECDH_Derive(SECItem *publicValue, |
357 | | ECParams *ecParams, |
358 | | SECItem *privateValue, |
359 | | PRBool withCofactor, |
360 | | SECItem *derivedSecret) |
361 | 69.1k | { |
362 | 69.1k | if (!publicValue || !publicValue->len || |
363 | 69.1k | !ecParams || ecParams->name == ECCurve_noName || |
364 | 69.1k | !privateValue || !privateValue->len || !derivedSecret) { |
365 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
366 | 0 | return SECFailure; |
367 | 0 | } |
368 | | |
369 | | /* |
370 | | * Make sure the point is on the requested curve to avoid |
371 | | * certain small subgroup attacks. |
372 | | */ |
373 | 69.1k | if (EC_ValidatePublicKey(ecParams, publicValue) != SECSuccess) { |
374 | 1.37k | PORT_SetError(SEC_ERROR_BAD_KEY); |
375 | 1.37k | return SECFailure; |
376 | 1.37k | } |
377 | | |
378 | | /* Perform curve specific multiplication using ECMethod */ |
379 | 67.7k | if (ecParams->fieldID.type != ec_field_plain) { |
380 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
381 | 0 | return SECFailure; |
382 | 0 | } |
383 | | |
384 | 67.7k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
385 | 67.7k | if (method == NULL || method->pt_validate == NULL || |
386 | 67.7k | method->pt_mul == NULL) { |
387 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
388 | 0 | return SECFailure; |
389 | 0 | } |
390 | | |
391 | 67.7k | memset(derivedSecret, 0, sizeof(*derivedSecret)); |
392 | 67.7k | derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, EC_GetScalarSize(ecParams)); |
393 | 67.7k | if (derivedSecret == NULL) { |
394 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
395 | 0 | return SECFailure; |
396 | 0 | } |
397 | | |
398 | 67.7k | SECStatus rv = method->pt_mul(derivedSecret, privateValue, publicValue); |
399 | 67.7k | if (rv != SECSuccess) { |
400 | 12.5k | PORT_SetError(SEC_ERROR_BAD_KEY); |
401 | 12.5k | SECITEM_ZfreeItem(derivedSecret, PR_FALSE); |
402 | 12.5k | } |
403 | 67.7k | return rv; |
404 | 67.7k | } |
405 | | |
406 | | /* Computes the ECDSA signature (a concatenation of two values r and s) |
407 | | * on the digest using the given key and the random value kb (used in |
408 | | * computing s). |
409 | | */ |
410 | | |
411 | | static SECStatus |
412 | | ec_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, |
413 | | const SECItem *digest, const unsigned char *kb, const int kblen) |
414 | 9.50k | { |
415 | 9.50k | ECParams *ecParams = NULL; |
416 | 9.50k | unsigned olen; /* length in bytes of the base point order */ |
417 | | |
418 | | /* Check args */ |
419 | 9.50k | if (!key || !signature || !digest || !kb || (kblen <= 0)) { |
420 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
421 | 0 | return SECFailure; |
422 | 0 | } |
423 | | |
424 | 9.50k | ecParams = &(key->ecParams); |
425 | 9.50k | olen = ecParams->order.len; |
426 | 9.50k | if (signature->data == NULL) { |
427 | | /* a call to get the signature length only */ |
428 | 0 | signature->len = 2 * olen; |
429 | 0 | return SECSuccess; |
430 | 0 | } |
431 | 9.50k | if (signature->len < 2 * olen) { |
432 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
433 | 0 | return SECFailure; |
434 | 0 | } |
435 | | |
436 | | /* Perform curve specific signature using ECMethod */ |
437 | 9.50k | if (ecParams->fieldID.type != ec_field_plain) { |
438 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
439 | 0 | return SECFailure; |
440 | 0 | } |
441 | | |
442 | 9.50k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
443 | 9.50k | if (method == NULL || method->sign_digest == NULL) { |
444 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
445 | 0 | return SECFailure; |
446 | 0 | } |
447 | | |
448 | 9.50k | SECStatus rv = method->sign_digest(key, signature, digest, kb, kblen); |
449 | 9.50k | if (rv != SECSuccess) { |
450 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
451 | 0 | } |
452 | | |
453 | | #if EC_DEBUG |
454 | | printf("ECDSA signing with seed %s\n", |
455 | | (rv == SECSuccess) ? "succeeded" : "failed"); |
456 | | #endif |
457 | 9.50k | return rv; |
458 | 9.50k | } |
459 | | |
460 | | SECStatus |
461 | | ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, |
462 | | const SECItem *digest, const unsigned char *kb, const int kblen) |
463 | 9.50k | { |
464 | | #if EC_DEBUG || EC_DOUBLECHECK |
465 | | SECItem *signature2 = SECITEM_AllocItem(NULL, NULL, signature->len); |
466 | | SECStatus signSuccess = ec_SignDigestWithSeed(key, signature, digest, kb, kblen); |
467 | | SECStatus signSuccessDouble = ec_SignDigestWithSeed(key, signature2, digest, kb, kblen); |
468 | | int signaturesEqual = NSS_SecureMemcmp(signature->data, signature2->data, signature->len); |
469 | | SECStatus rv; |
470 | | |
471 | | if ((signaturesEqual == 0) && (signSuccess == SECSuccess) && (signSuccessDouble == SECSuccess)) { |
472 | | rv = SECSuccess; |
473 | | } else { |
474 | | rv = SECFailure; |
475 | | } |
476 | | |
477 | | #if EC_DEBUG |
478 | | printf("ECDSA signing with seed %s after signing twice\n", (rv == SECSuccess) ? "succeeded" : "failed"); |
479 | | #endif |
480 | | |
481 | | SECITEM_FreeItem(signature2, PR_TRUE); |
482 | | return rv; |
483 | | #else |
484 | 9.50k | return ec_SignDigestWithSeed(key, signature, digest, kb, kblen); |
485 | 9.50k | #endif |
486 | 9.50k | } |
487 | | |
488 | | /* |
489 | | ** Computes the ECDSA signature on the digest using the given key |
490 | | ** and a random seed. |
491 | | */ |
492 | | SECStatus |
493 | | ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest) |
494 | 9.50k | { |
495 | 9.50k | SECItem nonceRand = { siBuffer, NULL, 0 }; |
496 | | |
497 | 9.50k | if (!key) { |
498 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
499 | 0 | return SECFailure; |
500 | 0 | } |
501 | | |
502 | | /* Generate random value k */ |
503 | 9.50k | SECITEM_AllocItem(NULL, &nonceRand, EC_GetScalarSize(&key->ecParams)); |
504 | 9.50k | if (nonceRand.data == NULL) { |
505 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
506 | 0 | return SECFailure; |
507 | 0 | } |
508 | | |
509 | 9.50k | SECStatus rv = ec_GenerateRandomPrivateKey(&key->ecParams, &nonceRand); |
510 | 9.50k | if (rv != SECSuccess) { |
511 | 0 | goto cleanup; |
512 | 0 | } |
513 | | |
514 | | /* Generate ECDSA signature with the specified k value */ |
515 | 9.50k | rv = ECDSA_SignDigestWithSeed(key, signature, digest, nonceRand.data, nonceRand.len); |
516 | 9.50k | NSS_DECLASSIFY(signature->data, signature->len); |
517 | | |
518 | 9.50k | cleanup: |
519 | 9.50k | SECITEM_ZfreeItem(&nonceRand, PR_FALSE); |
520 | | |
521 | | #if EC_DEBUG |
522 | | printf("ECDSA signing %s\n", |
523 | | (rv == SECSuccess) ? "succeeded" : "failed"); |
524 | | #endif |
525 | | |
526 | 9.50k | return rv; |
527 | 9.50k | } |
528 | | |
529 | | /* |
530 | | ** Checks the signature on the given digest using the key provided. |
531 | | ** |
532 | | ** The key argument must represent a valid EC public key (a point on |
533 | | ** the relevant curve). If it is not a valid point, then the behavior |
534 | | ** of this function is undefined. In cases where a public key might |
535 | | ** not be valid, use EC_ValidatePublicKey to check. |
536 | | */ |
537 | | SECStatus |
538 | | ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, |
539 | | const SECItem *digest) |
540 | 661 | { |
541 | 661 | SECStatus rv = SECFailure; |
542 | 661 | ECParams *ecParams = NULL; |
543 | | |
544 | | /* Check args */ |
545 | 661 | if (!key || !signature || !digest) { |
546 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
547 | 0 | return SECFailure; |
548 | 0 | } |
549 | | |
550 | 661 | ecParams = &(key->ecParams); |
551 | | |
552 | | /* Perform curve specific signature verification using ECMethod */ |
553 | 661 | if (ecParams->fieldID.type != ec_field_plain) { |
554 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
555 | 0 | return SECFailure; |
556 | 0 | } |
557 | | |
558 | 661 | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
559 | 661 | if (method == NULL || method->verify_digest == NULL) { |
560 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
561 | 0 | return SECFailure; |
562 | 0 | } |
563 | | |
564 | 661 | rv = method->verify_digest(key, signature, digest); |
565 | 661 | if (rv != SECSuccess) { |
566 | 562 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
567 | 562 | } |
568 | | |
569 | | #if EC_DEBUG |
570 | | printf("ECDSA verification %s\n", |
571 | | (rv == SECSuccess) ? "succeeded" : "failed"); |
572 | | #endif |
573 | | |
574 | 661 | return rv; |
575 | 661 | } |
576 | | |
577 | | /*EdDSA: Currently only Ed22519 is implemented.*/ |
578 | | |
579 | | /* |
580 | | ** Computes the EdDSA signature on the message using the given key. |
581 | | */ |
582 | | |
583 | | SECStatus |
584 | | ec_ED25519_public_key_validate(const ECPublicKey *key) |
585 | 0 | { |
586 | 0 | if (!key || !(key->ecParams.name == ECCurve_Ed25519)) { |
587 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
588 | 0 | return SECFailure; |
589 | 0 | } |
590 | 0 | return ec_ED25519_pt_validate(&key->publicValue); |
591 | 0 | } |
592 | | |
593 | | SECStatus |
594 | | ec_ED25519_private_key_validate(const ECPrivateKey *key) |
595 | 0 | { |
596 | 0 | if (!key || !(key->ecParams.name == ECCurve_Ed25519)) { |
597 | |
|
598 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
599 | 0 | return SECFailure; |
600 | 0 | } |
601 | 0 | return ec_ED25519_scalar_validate(&key->privateValue); |
602 | 0 | } |
603 | | |
604 | | SECStatus |
605 | | ED_SignMessage(ECPrivateKey *key, SECItem *signature, const SECItem *msg) |
606 | 0 | { |
607 | 0 | if (!msg || !signature || signature->len != Ed25519_SIGN_LEN) { |
608 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
609 | 0 | return SECFailure; |
610 | 0 | } |
611 | | |
612 | 0 | if (ec_ED25519_private_key_validate(key) != SECSuccess) { |
613 | 0 | return SECFailure; /* error code set by ec_ED25519_scalar_validate. */ |
614 | 0 | } |
615 | | |
616 | 0 | if (signature->data) { |
617 | 0 | Hacl_Ed25519_sign(signature->data, key->privateValue.data, msg->len, |
618 | 0 | msg->data); |
619 | 0 | } |
620 | 0 | signature->len = ED25519_SIGN_LEN; |
621 | 0 | BLAPI_CLEAR_STACK(2048); |
622 | 0 | return SECSuccess; |
623 | 0 | } |
624 | | |
625 | | /* |
626 | | ** Checks the signature on the given message using the key provided. |
627 | | */ |
628 | | |
629 | | SECStatus |
630 | | ED_VerifyMessage(ECPublicKey *key, const SECItem *signature, |
631 | | const SECItem *msg) |
632 | 0 | { |
633 | 0 | if (!msg || !signature || !signature->data || signature->len != Ed25519_SIGN_LEN) { |
634 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
635 | 0 | return SECFailure; |
636 | 0 | } |
637 | | |
638 | 0 | if (ec_ED25519_public_key_validate(key) != SECSuccess) { |
639 | 0 | return SECFailure; /* error code set by ec_ED25519_pt_validate. */ |
640 | 0 | } |
641 | | |
642 | 0 | bool rv = Hacl_Ed25519_verify(key->publicValue.data, msg->len, msg->data, |
643 | 0 | signature->data); |
644 | 0 | BLAPI_CLEAR_STACK(2048); |
645 | |
|
646 | | #if EC_DEBUG |
647 | | printf("ED_VerifyMessage returning %s\n", |
648 | | (rv) ? "success" : "failure"); |
649 | | #endif |
650 | |
|
651 | 0 | if (rv) { |
652 | 0 | return SECSuccess; |
653 | 0 | } |
654 | | |
655 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
656 | 0 | return SECFailure; |
657 | 0 | } |
658 | | |
659 | | SECStatus |
660 | | ED_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey) |
661 | 0 | { |
662 | | /* Currently supporting only Ed25519.*/ |
663 | 0 | if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != Ed25519_PUBLIC_KEYLEN) { |
664 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
665 | 0 | return SECFailure; |
666 | 0 | } |
667 | | |
668 | 0 | if (ec_ED25519_scalar_validate(privateKey) != SECSuccess) { |
669 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
670 | 0 | return SECFailure; |
671 | 0 | } |
672 | | |
673 | 0 | Hacl_Ed25519_secret_to_public(publicKey->data, privateKey->data); |
674 | 0 | return SECSuccess; |
675 | 0 | } |
676 | | |
677 | | SECStatus |
678 | | X25519_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey) |
679 | 0 | { |
680 | 0 | SECStatus rv = SECFailure; |
681 | | /* Currently supporting only X25519.*/ |
682 | 0 | if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != X25519_PUBLIC_KEYLEN) { |
683 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
684 | 0 | return SECFailure; |
685 | 0 | } |
686 | | |
687 | 0 | const ECMethod *method = ec_get_method_from_name(ECCurve25519); |
688 | 0 | if (method == NULL || method->pt_mul == NULL) { |
689 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
690 | 0 | return SECFailure; |
691 | 0 | } |
692 | | |
693 | 0 | rv = method->pt_mul(publicKey, (SECItem *)privateKey, NULL); |
694 | 0 | return rv; |
695 | 0 | } |
696 | | |
697 | | SECStatus |
698 | | EC_DerivePublicKey(const SECItem *privateKey, const ECParams *ecParams, SECItem *publicKey) |
699 | 69 | { |
700 | 69 | if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != EC_GetPointSize(ecParams)) { |
701 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
702 | 0 | return SECFailure; |
703 | 0 | } |
704 | | |
705 | 69 | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
706 | 69 | if (method == NULL || method->pt_mul == NULL) { |
707 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
708 | 0 | return SECFailure; |
709 | 0 | } |
710 | | |
711 | 69 | return method->pt_mul(publicKey, (SECItem *)privateKey, NULL); |
712 | 69 | } |