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_secp384r1_scalar_validate(const SECItem *scalar) |
27 | 5.51k | { |
28 | 5.51k | if (!scalar || !scalar->data) { |
29 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
30 | 0 | return SECFailure; |
31 | 0 | } |
32 | | |
33 | 5.51k | if (scalar->len != 48) { |
34 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
35 | 0 | return SECFailure; |
36 | 0 | } |
37 | | |
38 | 5.51k | bool b = Hacl_P384_validate_private_key(scalar->data); |
39 | | |
40 | 5.51k | if (!b) { |
41 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
42 | 0 | return SECFailure; |
43 | 0 | } |
44 | 5.51k | return SECSuccess; |
45 | 5.51k | } |
46 | | |
47 | | SECStatus |
48 | | ec_secp521r1_scalar_validate(const SECItem *scalar) |
49 | 964 | { |
50 | 964 | if (!scalar || !scalar->data) { |
51 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
52 | 0 | return SECFailure; |
53 | 0 | } |
54 | | |
55 | 964 | if (scalar->len != 66) { |
56 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
57 | 0 | return SECFailure; |
58 | 0 | } |
59 | | |
60 | 964 | bool b = Hacl_P521_validate_private_key(scalar->data); |
61 | | |
62 | 964 | if (!b) { |
63 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
64 | 0 | return SECFailure; |
65 | 0 | } |
66 | 964 | return SECSuccess; |
67 | 964 | } |
68 | | |
69 | | SECStatus |
70 | | ec_ED25519_pt_validate(const SECItem *px) |
71 | 0 | { |
72 | 0 | if (!px || !px->data || px->len != Ed25519_PUBLIC_KEYLEN) { |
73 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
74 | 0 | return SECFailure; |
75 | 0 | } |
76 | 0 | return SECSuccess; |
77 | 0 | } |
78 | | |
79 | | SECStatus |
80 | | ec_ED25519_scalar_validate(const SECItem *scalar) |
81 | 0 | { |
82 | 0 | if (!scalar || !scalar->data || scalar->len != Ed25519_PRIVATE_KEYLEN) { |
83 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
84 | 0 | return SECFailure; |
85 | 0 | } |
86 | | |
87 | 0 | return SECSuccess; |
88 | 0 | } |
89 | | |
90 | | static const ECMethod kMethods[] = { |
91 | | { ECCurve25519, |
92 | | ec_Curve25519_pt_mul, |
93 | | ec_Curve25519_pt_validate, |
94 | | ec_Curve25519_scalar_validate, |
95 | | NULL, |
96 | | NULL }, |
97 | | { |
98 | | ECCurve_NIST_P256, |
99 | | ec_secp256r1_pt_mul, |
100 | | ec_secp256r1_pt_validate, |
101 | | ec_secp256r1_scalar_validate, |
102 | | ec_secp256r1_sign_digest, |
103 | | ec_secp256r1_verify_digest, |
104 | | }, |
105 | | { |
106 | | ECCurve_NIST_P384, |
107 | | NULL, |
108 | | NULL, |
109 | | ec_secp384r1_scalar_validate, |
110 | | NULL, |
111 | | NULL, |
112 | | }, |
113 | | { |
114 | | ECCurve_NIST_P521, |
115 | | NULL, |
116 | | NULL, |
117 | | ec_secp521r1_scalar_validate, |
118 | | NULL, |
119 | | NULL, |
120 | | }, |
121 | | { ECCurve_Ed25519, |
122 | | NULL, |
123 | | ec_ED25519_pt_validate, |
124 | | ec_ED25519_scalar_validate, |
125 | | NULL, |
126 | | NULL }, |
127 | | }; |
128 | | |
129 | | static const ECMethod * |
130 | | ec_get_method_from_name(ECCurveName name) |
131 | 160k | { |
132 | 160k | unsigned long i; |
133 | 222k | for (i = 0; i < sizeof(kMethods) / sizeof(kMethods[0]); ++i) { |
134 | 222k | if (kMethods[i].name == name) { |
135 | 160k | return &kMethods[i]; |
136 | 160k | } |
137 | 222k | } |
138 | 0 | return NULL; |
139 | 160k | } |
140 | | |
141 | | /* |
142 | | * Returns true if pointP is the point at infinity, false otherwise |
143 | | */ |
144 | | PRBool |
145 | | ec_point_at_infinity(SECItem *pointP) |
146 | 14.2k | { |
147 | 14.2k | unsigned int i; |
148 | | |
149 | 16.1k | for (i = 1; i < pointP->len; i++) { |
150 | 16.1k | if (pointP->data[i] != 0x00) |
151 | 14.2k | return PR_FALSE; |
152 | 16.1k | } |
153 | | |
154 | 0 | return PR_TRUE; |
155 | 14.2k | } |
156 | | |
157 | | /* |
158 | | * Computes scalar point multiplication pointQ = k1 * G + k2 * pointP for |
159 | | * the curve whose parameters are encoded in params with base point G. |
160 | | */ |
161 | | SECStatus |
162 | | ec_points_mul(const ECParams *params, const mp_int *k1, const mp_int *k2, |
163 | | const SECItem *pointP, SECItem *pointQ) |
164 | 14.1k | { |
165 | 14.1k | mp_int Px, Py, Qx, Qy; |
166 | 14.1k | mp_int Gx, Gy, order, irreducible, a, b; |
167 | 14.1k | ECGroup *group = NULL; |
168 | 14.1k | SECStatus rv = SECFailure; |
169 | 14.1k | mp_err err = MP_OKAY; |
170 | 14.1k | unsigned int len; |
171 | | |
172 | | #if EC_DEBUG |
173 | | int i; |
174 | | char mpstr[256]; |
175 | | |
176 | | printf("ec_points_mul: params [len=%d]:", params->DEREncoding.len); |
177 | | for (i = 0; i < params->DEREncoding.len; i++) |
178 | | printf("%02x:", params->DEREncoding.data[i]); |
179 | | printf("\n"); |
180 | | |
181 | | if (k1 != NULL) { |
182 | | mp_tohex((mp_int *)k1, mpstr); |
183 | | printf("ec_points_mul: scalar k1: %s\n", mpstr); |
184 | | mp_todecimal((mp_int *)k1, mpstr); |
185 | | printf("ec_points_mul: scalar k1: %s (dec)\n", mpstr); |
186 | | } |
187 | | |
188 | | if (k2 != NULL) { |
189 | | mp_tohex((mp_int *)k2, mpstr); |
190 | | printf("ec_points_mul: scalar k2: %s\n", mpstr); |
191 | | mp_todecimal((mp_int *)k2, mpstr); |
192 | | printf("ec_points_mul: scalar k2: %s (dec)\n", mpstr); |
193 | | } |
194 | | |
195 | | if (pointP != NULL) { |
196 | | printf("ec_points_mul: pointP [len=%d]:", pointP->len); |
197 | | for (i = 0; i < pointP->len; i++) |
198 | | printf("%02x:", pointP->data[i]); |
199 | | printf("\n"); |
200 | | } |
201 | | #endif |
202 | | |
203 | | /* NOTE: We only support uncompressed points for now */ |
204 | 14.1k | len = (((unsigned int)params->fieldID.size) + 7) >> 3; |
205 | 14.1k | if (pointP != NULL) { |
206 | 7.68k | if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || |
207 | 7.68k | (pointP->len != (2 * len + 1))) { |
208 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
209 | 0 | return SECFailure; |
210 | 7.68k | }; |
211 | 7.68k | } |
212 | | |
213 | 14.1k | MP_DIGITS(&Px) = 0; |
214 | 14.1k | MP_DIGITS(&Py) = 0; |
215 | 14.1k | MP_DIGITS(&Qx) = 0; |
216 | 14.1k | MP_DIGITS(&Qy) = 0; |
217 | 14.1k | MP_DIGITS(&Gx) = 0; |
218 | 14.1k | MP_DIGITS(&Gy) = 0; |
219 | 14.1k | MP_DIGITS(&order) = 0; |
220 | 14.1k | MP_DIGITS(&irreducible) = 0; |
221 | 14.1k | MP_DIGITS(&a) = 0; |
222 | 14.1k | MP_DIGITS(&b) = 0; |
223 | 14.1k | CHECK_MPI_OK(mp_init(&Px)); |
224 | 14.1k | CHECK_MPI_OK(mp_init(&Py)); |
225 | 14.1k | CHECK_MPI_OK(mp_init(&Qx)); |
226 | 14.1k | CHECK_MPI_OK(mp_init(&Qy)); |
227 | 14.1k | CHECK_MPI_OK(mp_init(&Gx)); |
228 | 14.1k | CHECK_MPI_OK(mp_init(&Gy)); |
229 | 14.1k | CHECK_MPI_OK(mp_init(&order)); |
230 | 14.1k | CHECK_MPI_OK(mp_init(&irreducible)); |
231 | 14.1k | CHECK_MPI_OK(mp_init(&a)); |
232 | 14.1k | CHECK_MPI_OK(mp_init(&b)); |
233 | | |
234 | 14.1k | if ((k2 != NULL) && (pointP != NULL)) { |
235 | | /* Initialize Px and Py */ |
236 | 7.68k | CHECK_MPI_OK(mp_read_unsigned_octets(&Px, pointP->data + 1, (mp_size)len)); |
237 | 7.68k | CHECK_MPI_OK(mp_read_unsigned_octets(&Py, pointP->data + 1 + len, (mp_size)len)); |
238 | 7.68k | } |
239 | | |
240 | | /* construct from named params, if possible */ |
241 | 14.1k | if (params->name != ECCurve_noName) { |
242 | 14.1k | group = ECGroup_fromName(params->name); |
243 | 14.1k | } |
244 | | |
245 | 14.1k | if (group == NULL) |
246 | 0 | goto cleanup; |
247 | | |
248 | 14.1k | if ((k2 != NULL) && (pointP != NULL)) { |
249 | 7.68k | CHECK_MPI_OK(ECPoints_mul(group, k1, k2, &Px, &Py, &Qx, &Qy)); |
250 | 7.68k | } else { |
251 | 6.47k | CHECK_MPI_OK(ECPoints_mul(group, k1, NULL, NULL, NULL, &Qx, &Qy)); |
252 | 6.47k | } |
253 | | |
254 | | /* our ECC codes uses large stack variables to store intermediate results, |
255 | | * clear our stack before returning to prevent CSP leakage */ |
256 | 14.1k | BLAPI_CLEAR_STACK(2048) |
257 | | |
258 | | /* Construct the SECItem representation of point Q */ |
259 | 14.1k | pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED; |
260 | 14.1k | CHECK_MPI_OK(mp_to_fixlen_octets(&Qx, pointQ->data + 1, |
261 | 14.1k | (mp_size)len)); |
262 | 14.1k | CHECK_MPI_OK(mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len, |
263 | 14.1k | (mp_size)len)); |
264 | | |
265 | 14.1k | rv = SECSuccess; |
266 | | |
267 | | #if EC_DEBUG |
268 | | printf("ec_points_mul: pointQ [len=%d]:", pointQ->len); |
269 | | for (i = 0; i < pointQ->len; i++) |
270 | | printf("%02x:", pointQ->data[i]); |
271 | | printf("\n"); |
272 | | #endif |
273 | | |
274 | 14.1k | cleanup: |
275 | 14.1k | ECGroup_free(group); |
276 | 14.1k | mp_clear(&Px); |
277 | 14.1k | mp_clear(&Py); |
278 | 14.1k | mp_clear(&Qx); |
279 | 14.1k | mp_clear(&Qy); |
280 | 14.1k | mp_clear(&Gx); |
281 | 14.1k | mp_clear(&Gy); |
282 | 14.1k | mp_clear(&order); |
283 | 14.1k | mp_clear(&irreducible); |
284 | 14.1k | mp_clear(&a); |
285 | 14.1k | mp_clear(&b); |
286 | 14.1k | if (err) { |
287 | 0 | MP_TO_SEC_ERROR(err); |
288 | 0 | rv = SECFailure; |
289 | 0 | } |
290 | | |
291 | 14.1k | return rv; |
292 | 14.1k | } |
293 | | |
294 | | /* Generates a new EC key pair. The private key is a supplied |
295 | | * value and the public key is the result of performing a scalar |
296 | | * point multiplication of that value with the curve's base point. |
297 | | */ |
298 | | SECStatus |
299 | | ec_NewKey(ECParams *ecParams, ECPrivateKey **privKey, |
300 | | const unsigned char *privKeyBytes, int privKeyLen) |
301 | 34.8k | { |
302 | 34.8k | SECStatus rv = SECFailure; |
303 | 34.8k | PLArenaPool *arena; |
304 | 34.8k | ECPrivateKey *key; |
305 | 34.8k | mp_int k; |
306 | 34.8k | mp_err err = MP_OKAY; |
307 | 34.8k | int len; |
308 | | |
309 | | #if EC_DEBUG |
310 | | printf("ec_NewKey called\n"); |
311 | | #endif |
312 | 34.8k | MP_DIGITS(&k) = 0; |
313 | | |
314 | 34.8k | if (!ecParams || ecParams->name == ECCurve_noName || |
315 | 34.8k | !privKey || !privKeyBytes || privKeyLen <= 0) { |
316 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
317 | 0 | return SECFailure; |
318 | 0 | } |
319 | | |
320 | | /* Initialize an arena for the EC key. */ |
321 | 34.8k | if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) |
322 | 0 | return SECFailure; |
323 | | |
324 | 34.8k | key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey)); |
325 | 34.8k | if (!key) { |
326 | 0 | PORT_FreeArena(arena, PR_TRUE); |
327 | 0 | return SECFailure; |
328 | 0 | } |
329 | | |
330 | | /* Set the version number (SEC 1 section C.4 says it should be 1) */ |
331 | 34.8k | SECITEM_AllocItem(arena, &key->version, 1); |
332 | 34.8k | key->version.data[0] = 1; |
333 | | |
334 | | /* Copy all of the fields from the ECParams argument to the |
335 | | * ECParams structure within the private key. |
336 | | */ |
337 | 34.8k | key->ecParams.arena = arena; |
338 | 34.8k | key->ecParams.type = ecParams->type; |
339 | 34.8k | key->ecParams.fieldID.size = ecParams->fieldID.size; |
340 | 34.8k | key->ecParams.fieldID.type = ecParams->fieldID.type; |
341 | 34.8k | if (ecParams->fieldID.type == ec_field_GFp || |
342 | 34.8k | ecParams->fieldID.type == ec_field_plain) { |
343 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime, |
344 | 34.8k | &ecParams->fieldID.u.prime)); |
345 | 34.8k | } else { |
346 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.poly, |
347 | 0 | &ecParams->fieldID.u.poly)); |
348 | 0 | } |
349 | 34.8k | key->ecParams.fieldID.k1 = ecParams->fieldID.k1; |
350 | 34.8k | key->ecParams.fieldID.k2 = ecParams->fieldID.k2; |
351 | 34.8k | key->ecParams.fieldID.k3 = ecParams->fieldID.k3; |
352 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a, |
353 | 34.8k | &ecParams->curve.a)); |
354 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b, |
355 | 34.8k | &ecParams->curve.b)); |
356 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed, |
357 | 34.8k | &ecParams->curve.seed)); |
358 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base, |
359 | 34.8k | &ecParams->base)); |
360 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order, |
361 | 34.8k | &ecParams->order)); |
362 | 34.8k | key->ecParams.cofactor = ecParams->cofactor; |
363 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding, |
364 | 34.8k | &ecParams->DEREncoding)); |
365 | 34.8k | key->ecParams.name = ecParams->name; |
366 | 34.8k | CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curveOID, |
367 | 34.8k | &ecParams->curveOID)); |
368 | | |
369 | 34.8k | SECITEM_AllocItem(arena, &key->publicValue, EC_GetPointSize(ecParams)); |
370 | 34.8k | len = ecParams->order.len; |
371 | 34.8k | SECITEM_AllocItem(arena, &key->privateValue, len); |
372 | | |
373 | | /* Copy private key */ |
374 | 34.8k | if (privKeyLen >= len) { |
375 | 34.8k | memcpy(key->privateValue.data, privKeyBytes, len); |
376 | 34.8k | } else { |
377 | 0 | memset(key->privateValue.data, 0, (len - privKeyLen)); |
378 | 0 | memcpy(key->privateValue.data + (len - privKeyLen), privKeyBytes, privKeyLen); |
379 | 0 | } |
380 | | |
381 | | /* Compute corresponding public key */ |
382 | | |
383 | | /* Use curve specific code for point multiplication */ |
384 | | |
385 | 34.8k | if (ecParams->name == ECCurve_Ed25519) { |
386 | 0 | rv = ED_DerivePublicKey(&key->privateValue, &key->publicValue); |
387 | 0 | if (rv != SECSuccess) { |
388 | 0 | goto cleanup; |
389 | 0 | } |
390 | 0 | NSS_DECLASSIFY(key->publicValue.data, key->publicValue.len); /* Declassifying public key to avoid false positive */ |
391 | 0 | goto done; |
392 | 0 | } |
393 | | |
394 | 34.8k | if (ecParams->fieldID.type == ec_field_plain) { |
395 | 28.3k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
396 | 28.3k | if (method == NULL || method->pt_mul == NULL) { |
397 | | /* unknown curve */ |
398 | 0 | rv = SECFailure; |
399 | 0 | goto cleanup; |
400 | 0 | } |
401 | 28.3k | rv = method->pt_mul(&key->publicValue, &key->privateValue, NULL); |
402 | 28.3k | NSS_DECLASSIFY(key->publicValue.data, key->publicValue.len); /* Declassifying public key to avoid false positive */ |
403 | 28.3k | if (rv != SECSuccess) { |
404 | 0 | goto cleanup; |
405 | 28.3k | } else { |
406 | 28.3k | goto done; |
407 | 28.3k | } |
408 | 28.3k | } |
409 | | |
410 | 6.47k | CHECK_MPI_OK(mp_init(&k)); |
411 | 6.47k | CHECK_MPI_OK(mp_read_unsigned_octets(&k, key->privateValue.data, |
412 | 6.47k | (mp_size)len)); |
413 | | |
414 | 6.47k | rv = ec_points_mul(ecParams, &k, NULL, NULL, &(key->publicValue)); |
415 | 6.47k | NSS_DECLASSIFY(key->publicValue.data, key->publicValue.len); /* Declassifying public key to avoid false positive */ |
416 | 6.47k | if (rv != SECSuccess) { |
417 | 0 | goto cleanup; |
418 | 0 | } |
419 | | |
420 | 34.8k | done: |
421 | 34.8k | *privKey = key; |
422 | | |
423 | 34.8k | cleanup: |
424 | 34.8k | mp_clear(&k); |
425 | 34.8k | if (rv) { |
426 | 0 | PORT_FreeArena(arena, PR_TRUE); |
427 | 0 | } |
428 | | |
429 | | #if EC_DEBUG |
430 | | printf("ec_NewKey returning %s\n", |
431 | | (rv == SECSuccess) ? "success" : "failure"); |
432 | | #endif |
433 | | |
434 | 34.8k | return rv; |
435 | 34.8k | } |
436 | | |
437 | | /* Generates a new EC key pair. The private key is a supplied |
438 | | * random value (in seed) and the public key is the result of |
439 | | * performing a scalar point multiplication of that value with |
440 | | * the curve's base point. |
441 | | */ |
442 | | SECStatus |
443 | | EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, |
444 | | const unsigned char *seed, int seedlen) |
445 | 0 | { |
446 | 0 | SECStatus rv = SECFailure; |
447 | 0 | rv = ec_NewKey(ecParams, privKey, seed, seedlen); |
448 | 0 | return rv; |
449 | 0 | } |
450 | | |
451 | | /* Generate a random private key using the algorithm A.4.1 or A.4.2 of ANSI X9.62, |
452 | | * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the |
453 | | * random number generator. |
454 | | */ |
455 | | |
456 | | SECStatus |
457 | | ec_GenerateRandomPrivateKey(ECParams *ecParams, SECItem *privKey) |
458 | 36.1k | { |
459 | 36.1k | SECStatus rv = SECFailure; |
460 | | |
461 | 36.1k | unsigned int len = EC_GetScalarSize(ecParams); |
462 | | |
463 | 36.1k | if (privKey->len != len || privKey->data == NULL) { |
464 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
465 | 0 | return SECFailure; |
466 | 0 | } |
467 | | |
468 | 36.1k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
469 | 36.1k | if (method == NULL || method->scalar_validate == NULL) { |
470 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
471 | 0 | return SECFailure; |
472 | 0 | } |
473 | | |
474 | 36.1k | uint8_t leading_coeff_mask; |
475 | 36.1k | switch (ecParams->name) { |
476 | 0 | case ECCurve_Ed25519: |
477 | 20.8k | case ECCurve25519: |
478 | 29.6k | case ECCurve_NIST_P256: |
479 | 35.1k | case ECCurve_NIST_P384: |
480 | 35.1k | leading_coeff_mask = 0xff; |
481 | 35.1k | break; |
482 | 964 | case ECCurve_NIST_P521: |
483 | 964 | leading_coeff_mask = 0x01; |
484 | 964 | break; |
485 | 0 | default: |
486 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
487 | 0 | return SECFailure; |
488 | 36.1k | } |
489 | | |
490 | | /* The rejection sampling method from FIPS 186-5 A.4.2 */ |
491 | 36.1k | int count = 100; |
492 | 36.1k | do { |
493 | 36.1k | rv = RNG_GenerateGlobalRandomBytes(privKey->data, len); |
494 | 36.1k | if (rv != SECSuccess) { |
495 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
496 | 0 | return SECFailure; |
497 | 0 | } |
498 | 36.1k | privKey->data[0] &= leading_coeff_mask; |
499 | 36.1k | NSS_CLASSIFY(privKey->data, privKey->len); |
500 | 36.1k | rv = method->scalar_validate(privKey); |
501 | 36.1k | } while (rv != SECSuccess && --count > 0); |
502 | | |
503 | 36.1k | if (rv != SECSuccess) { // implies count == 0 |
504 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
505 | 0 | } |
506 | | |
507 | 36.1k | return rv; |
508 | 36.1k | } |
509 | | |
510 | | /* Generates a new EC key pair. The private key is a random value and |
511 | | * the public key is the result of performing a scalar point multiplication |
512 | | * of that value with the curve's base point. |
513 | | */ |
514 | | SECStatus |
515 | | EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey) |
516 | 34.8k | { |
517 | 34.8k | SECStatus rv = SECFailure; |
518 | 34.8k | SECItem privKeyRand = { siBuffer, NULL, 0 }; |
519 | | |
520 | 34.8k | if (!ecParams || ecParams->name == ECCurve_noName || !privKey) { |
521 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
522 | 0 | return SECFailure; |
523 | 0 | } |
524 | | |
525 | 34.8k | SECITEM_AllocItem(NULL, &privKeyRand, EC_GetScalarSize(ecParams)); |
526 | 34.8k | if (privKeyRand.data == NULL) { |
527 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
528 | 0 | rv = SECFailure; |
529 | 0 | goto cleanup; |
530 | 0 | } |
531 | 34.8k | rv = ec_GenerateRandomPrivateKey(ecParams, &privKeyRand); |
532 | 34.8k | if (rv != SECSuccess || privKeyRand.data == NULL) { |
533 | 0 | goto cleanup; |
534 | 0 | } |
535 | | /* generate public key */ |
536 | 34.8k | CHECK_SEC_OK(ec_NewKey(ecParams, privKey, privKeyRand.data, privKeyRand.len)); |
537 | | |
538 | 34.8k | cleanup: |
539 | 34.8k | if (privKeyRand.data) { |
540 | 34.8k | SECITEM_ZfreeItem(&privKeyRand, PR_FALSE); |
541 | 34.8k | } |
542 | | #if EC_DEBUG |
543 | | printf("EC_NewKey returning %s\n", |
544 | | (rv == SECSuccess) ? "success" : "failure"); |
545 | | #endif |
546 | | |
547 | 34.8k | return rv; |
548 | 34.8k | } |
549 | | |
550 | | /* Validates an EC public key as described in Section 5.2.2 of |
551 | | * X9.62. The ECDH primitive when used without the cofactor does |
552 | | * not address small subgroup attacks, which may occur when the |
553 | | * public key is not valid. These attacks can be prevented by |
554 | | * validating the public key before using ECDH. |
555 | | */ |
556 | | SECStatus |
557 | | EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue) |
558 | 81.6k | { |
559 | 81.6k | mp_int Px, Py; |
560 | 81.6k | ECGroup *group = NULL; |
561 | 81.6k | SECStatus rv = SECFailure; |
562 | 81.6k | mp_err err = MP_OKAY; |
563 | 81.6k | unsigned int len; |
564 | | |
565 | 81.6k | if (!ecParams || ecParams->name == ECCurve_noName || |
566 | 81.6k | !publicValue || !publicValue->len) { |
567 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
568 | 0 | rv = SECFailure; |
569 | 0 | return rv; |
570 | 0 | } |
571 | | |
572 | | /* Uses curve specific code for point validation. */ |
573 | 81.6k | if (ecParams->fieldID.type == ec_field_plain) { |
574 | 61.9k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
575 | 61.9k | if (method == NULL || method->pt_validate == NULL) { |
576 | | /* unknown curve */ |
577 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
578 | 0 | rv = SECFailure; |
579 | 0 | return rv; |
580 | 0 | } |
581 | 61.9k | rv = method->pt_validate(publicValue); |
582 | 61.9k | if (rv != SECSuccess) { |
583 | 343 | PORT_SetError(SEC_ERROR_BAD_KEY); |
584 | 343 | } |
585 | 61.9k | return rv; |
586 | 61.9k | } |
587 | | |
588 | | /* NOTE: We only support uncompressed points for now */ |
589 | 19.7k | len = (((unsigned int)ecParams->fieldID.size) + 7) >> 3; |
590 | 19.7k | if (publicValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) { |
591 | 21 | PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); |
592 | 21 | return SECFailure; |
593 | 19.7k | } else if (publicValue->len != (2 * len + 1)) { |
594 | 30 | PORT_SetError(SEC_ERROR_BAD_KEY); |
595 | 30 | return SECFailure; |
596 | 30 | } |
597 | | |
598 | 19.6k | MP_DIGITS(&Px) = 0; |
599 | 19.6k | MP_DIGITS(&Py) = 0; |
600 | 19.6k | CHECK_MPI_OK(mp_init(&Px)); |
601 | 19.6k | CHECK_MPI_OK(mp_init(&Py)); |
602 | | |
603 | | /* Initialize Px and Py */ |
604 | 19.6k | CHECK_MPI_OK(mp_read_unsigned_octets(&Px, publicValue->data + 1, (mp_size)len)); |
605 | 19.6k | CHECK_MPI_OK(mp_read_unsigned_octets(&Py, publicValue->data + 1 + len, (mp_size)len)); |
606 | | |
607 | | /* construct from named params */ |
608 | 19.6k | group = ECGroup_fromName(ecParams->name); |
609 | 19.6k | if (group == NULL) { |
610 | | /* |
611 | | * ECGroup_fromName fails if ecParams->name is not a valid |
612 | | * ECCurveName value, or if we run out of memory, or perhaps |
613 | | * for other reasons. Unfortunately if ecParams->name is a |
614 | | * valid ECCurveName value, we don't know what the right error |
615 | | * code should be because ECGroup_fromName doesn't return an |
616 | | * error code to the caller. Set err to MP_UNDEF because |
617 | | * that's what ECGroup_fromName uses internally. |
618 | | */ |
619 | 0 | if ((ecParams->name <= ECCurve_noName) || |
620 | 0 | (ecParams->name >= ECCurve_pastLastCurve)) { |
621 | 0 | err = MP_BADARG; |
622 | 0 | } else { |
623 | 0 | err = MP_UNDEF; |
624 | 0 | } |
625 | 0 | goto cleanup; |
626 | 0 | } |
627 | | |
628 | | /* validate public point */ |
629 | 19.6k | if ((err = ECPoint_validate(group, &Px, &Py)) < MP_YES) { |
630 | 5.50k | if (err == MP_NO) { |
631 | 5.50k | PORT_SetError(SEC_ERROR_BAD_KEY); |
632 | 5.50k | rv = SECFailure; |
633 | 5.50k | err = MP_OKAY; /* don't change the error code */ |
634 | 5.50k | } |
635 | 5.50k | goto cleanup; |
636 | 5.50k | } |
637 | | |
638 | 14.1k | rv = SECSuccess; |
639 | | |
640 | 19.6k | cleanup: |
641 | 19.6k | ECGroup_free(group); |
642 | 19.6k | mp_clear(&Px); |
643 | 19.6k | mp_clear(&Py); |
644 | | |
645 | 19.6k | if (err) { |
646 | 0 | MP_TO_SEC_ERROR(err); |
647 | 0 | rv = SECFailure; |
648 | 0 | } |
649 | 19.6k | return rv; |
650 | 19.6k | } |
651 | | |
652 | | /* |
653 | | ** Performs an ECDH key derivation by computing the scalar point |
654 | | ** multiplication of privateValue and publicValue (with or without the |
655 | | ** cofactor) and returns the x-coordinate of the resulting elliptic |
656 | | ** curve point in derived secret. If successful, derivedSecret->data |
657 | | ** is set to the address of the newly allocated buffer containing the |
658 | | ** derived secret, and derivedSecret->len is the size of the secret |
659 | | ** produced. It is the caller's responsibility to free the allocated |
660 | | ** buffer containing the derived secret. |
661 | | */ |
662 | | SECStatus |
663 | | ECDH_Derive(SECItem *publicValue, |
664 | | ECParams *ecParams, |
665 | | SECItem *privateValue, |
666 | | PRBool withCofactor, |
667 | | SECItem *derivedSecret) |
668 | 42.7k | { |
669 | 42.7k | SECStatus rv = SECFailure; |
670 | 42.7k | unsigned int len = 0; |
671 | 42.7k | mp_err err = MP_OKAY; |
672 | | |
673 | 42.7k | if (!publicValue || !publicValue->len || |
674 | 42.7k | !ecParams || ecParams->name == ECCurve_noName || |
675 | 42.7k | !privateValue || !privateValue->len || !derivedSecret) { |
676 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
677 | 0 | rv = SECFailure; |
678 | 0 | return rv; |
679 | 0 | } |
680 | | |
681 | | /* |
682 | | * Make sure the point is on the requested curve to avoid |
683 | | * certain small subgroup attacks. |
684 | | */ |
685 | 42.7k | if (EC_ValidatePublicKey(ecParams, publicValue) != SECSuccess) { |
686 | 3.20k | PORT_SetError(SEC_ERROR_BAD_KEY); |
687 | 3.20k | rv = SECFailure; |
688 | 3.20k | return rv; |
689 | 3.20k | } |
690 | | |
691 | | /* Perform curve specific multiplication using ECMethod */ |
692 | 39.5k | if (ecParams->fieldID.type == ec_field_plain) { |
693 | 32.9k | const ECMethod *method; |
694 | 32.9k | memset(derivedSecret, 0, sizeof(*derivedSecret)); |
695 | 32.9k | derivedSecret = SECITEM_AllocItem(NULL, derivedSecret, EC_GetScalarSize(ecParams)); |
696 | 32.9k | if (derivedSecret == NULL) { |
697 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
698 | 0 | rv = SECFailure; |
699 | 0 | return rv; |
700 | 0 | } |
701 | 32.9k | method = ec_get_method_from_name(ecParams->name); |
702 | 32.9k | if (method == NULL || method->pt_validate == NULL || |
703 | 32.9k | method->pt_mul == NULL) { |
704 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
705 | 0 | rv = SECFailure; |
706 | 0 | goto done; |
707 | 0 | } |
708 | 32.9k | rv = method->pt_mul(derivedSecret, privateValue, publicValue); |
709 | 32.9k | if (rv != SECSuccess) { |
710 | 1 | PORT_SetError(SEC_ERROR_BAD_KEY); |
711 | 1 | } |
712 | 32.9k | goto done; |
713 | 32.9k | } |
714 | | |
715 | 6.60k | SECItem pointQ = { siBuffer, NULL, 0 }; |
716 | 6.60k | mp_int k; /* to hold the private value */ |
717 | | #if EC_DEBUG |
718 | | int i; |
719 | | #endif |
720 | | |
721 | | /* |
722 | | * We fail if the public value is the point at infinity, since |
723 | | * this produces predictable results. |
724 | | */ |
725 | 6.60k | if (ec_point_at_infinity(publicValue)) { |
726 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); |
727 | 0 | return SECFailure; |
728 | 0 | } |
729 | | |
730 | 6.60k | MP_DIGITS(&k) = 0; |
731 | 6.60k | memset(derivedSecret, 0, sizeof *derivedSecret); |
732 | 6.60k | len = (ecParams->fieldID.size + 7) >> 3; |
733 | 6.60k | pointQ.len = EC_GetPointSize(ecParams); |
734 | 6.60k | if ((pointQ.data = PORT_Alloc(pointQ.len)) == NULL) |
735 | 0 | goto cleanup; |
736 | | |
737 | 6.60k | CHECK_MPI_OK(mp_init(&k)); |
738 | 6.60k | CHECK_MPI_OK(mp_read_unsigned_octets(&k, privateValue->data, |
739 | 6.60k | (mp_size)privateValue->len)); |
740 | | |
741 | 6.60k | if (withCofactor && (ecParams->cofactor != 1)) { |
742 | 0 | mp_int cofactor; |
743 | | /* multiply k with the cofactor */ |
744 | 0 | MP_DIGITS(&cofactor) = 0; |
745 | 0 | CHECK_MPI_OK(mp_init(&cofactor)); |
746 | 0 | mp_set(&cofactor, ecParams->cofactor); |
747 | 0 | CHECK_MPI_OK(mp_mul(&k, &cofactor, &k)); |
748 | 0 | mp_clear(&cofactor); |
749 | 0 | } |
750 | | |
751 | | /* Multiply our private key and peer's public point */ |
752 | 6.60k | if (ec_points_mul(ecParams, NULL, &k, publicValue, &pointQ) != SECSuccess) { |
753 | 0 | goto cleanup; |
754 | 0 | } |
755 | 6.60k | if (ec_point_at_infinity(&pointQ)) { |
756 | 0 | PORT_SetError(SEC_ERROR_BAD_KEY); /* XXX better error code? */ |
757 | 0 | goto cleanup; |
758 | 0 | } |
759 | | |
760 | | /* Allocate memory for the derived secret and copy |
761 | | * the x co-ordinate of pointQ into it. |
762 | | */ |
763 | 6.60k | SECITEM_AllocItem(NULL, derivedSecret, len); |
764 | 6.60k | memcpy(derivedSecret->data, pointQ.data + 1, len); |
765 | | |
766 | 6.60k | rv = SECSuccess; |
767 | | |
768 | | #if EC_DEBUG |
769 | | printf("derived_secret:\n"); |
770 | | for (i = 0; i < derivedSecret->len; i++) |
771 | | printf("%02x:", derivedSecret->data[i]); |
772 | | printf("\n"); |
773 | | #endif |
774 | | |
775 | 6.60k | cleanup: |
776 | 6.60k | mp_clear(&k); |
777 | | |
778 | 6.60k | if (pointQ.data) { |
779 | 6.60k | PORT_ZFree(pointQ.data, pointQ.len); |
780 | 6.60k | } |
781 | | |
782 | 39.5k | done: |
783 | | |
784 | 39.5k | if (err) { |
785 | 0 | MP_TO_SEC_ERROR(err); |
786 | 0 | } |
787 | 39.5k | if (rv != SECSuccess) { |
788 | 1 | SECITEM_ZfreeItem(derivedSecret, PR_FALSE); |
789 | 1 | } |
790 | 39.5k | return rv; |
791 | 39.5k | } |
792 | | |
793 | | /* Computes the ECDSA signature (a concatenation of two values r and s) |
794 | | * on the digest using the given key and the random value kb (used in |
795 | | * computing s). |
796 | | */ |
797 | | |
798 | | static SECStatus |
799 | | ec_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, |
800 | | const SECItem *digest, const unsigned char *kb, const int kblen) |
801 | 1.30k | { |
802 | 1.30k | SECStatus rv = SECFailure; |
803 | 1.30k | ECParams *ecParams = NULL; |
804 | 1.30k | mp_err err = MP_OKAY; |
805 | 1.30k | int flen = 0; /* length in bytes of the field size */ |
806 | 1.30k | unsigned olen; /* length in bytes of the base point order */ |
807 | | |
808 | | /* Check args */ |
809 | 1.30k | if (!key || !signature || !digest || !kb || (kblen <= 0)) { |
810 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
811 | 0 | rv = SECFailure; |
812 | 0 | goto done; |
813 | 0 | } |
814 | | |
815 | 1.30k | ecParams = &(key->ecParams); |
816 | 1.30k | flen = (ecParams->fieldID.size + 7) >> 3; |
817 | 1.30k | olen = ecParams->order.len; |
818 | 1.30k | if (signature->data == NULL) { |
819 | | /* a call to get the signature length only */ |
820 | 0 | signature->len = 2 * olen; |
821 | 0 | rv = SECSuccess; |
822 | 0 | goto done; |
823 | 0 | } |
824 | 1.30k | if (signature->len < 2 * olen) { |
825 | 0 | PORT_SetError(SEC_ERROR_OUTPUT_LEN); |
826 | 0 | rv = SECFailure; |
827 | 0 | goto done; |
828 | 0 | } |
829 | | |
830 | | /* Perform curve specific signature using ECMethod */ |
831 | 1.30k | if (ecParams->fieldID.type == ec_field_plain) { |
832 | 1.30k | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
833 | 1.30k | if (method == NULL || method->sign_digest == NULL) { |
834 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
835 | 0 | rv = SECFailure; |
836 | 0 | goto done; |
837 | 0 | } |
838 | 1.30k | rv = method->sign_digest(key, signature, digest, kb, kblen); |
839 | 1.30k | if (rv != SECSuccess) { |
840 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
841 | 0 | } |
842 | 1.30k | goto done; |
843 | 1.30k | } |
844 | | |
845 | 0 | mp_int x1; |
846 | 0 | mp_int d, k; /* private key, random integer */ |
847 | 0 | mp_int r, s; /* tuple (r, s) is the signature */ |
848 | 0 | mp_int t; /* holding tmp values */ |
849 | 0 | mp_int n; |
850 | 0 | mp_int ar; /* blinding value */ |
851 | 0 | SECItem kGpoint = { siBuffer, NULL, 0 }; |
852 | 0 | unsigned char *t2 = NULL; |
853 | 0 | unsigned obits; /* length in bits of the base point order */ |
854 | |
|
855 | | #if EC_DEBUG |
856 | | char mpstr[256]; |
857 | | #endif |
858 | | |
859 | | /* Initialize MPI integers. */ |
860 | | /* must happen before the first potential call to cleanup */ |
861 | 0 | MP_DIGITS(&x1) = 0; |
862 | 0 | MP_DIGITS(&d) = 0; |
863 | 0 | MP_DIGITS(&k) = 0; |
864 | 0 | MP_DIGITS(&r) = 0; |
865 | 0 | MP_DIGITS(&s) = 0; |
866 | 0 | MP_DIGITS(&n) = 0; |
867 | 0 | MP_DIGITS(&t) = 0; |
868 | 0 | MP_DIGITS(&ar) = 0; |
869 | |
|
870 | 0 | CHECK_MPI_OK(mp_init(&x1)); |
871 | 0 | CHECK_MPI_OK(mp_init(&d)); |
872 | 0 | CHECK_MPI_OK(mp_init(&k)); |
873 | 0 | CHECK_MPI_OK(mp_init(&r)); |
874 | 0 | CHECK_MPI_OK(mp_init(&s)); |
875 | 0 | CHECK_MPI_OK(mp_init(&n)); |
876 | 0 | CHECK_MPI_OK(mp_init(&t)); |
877 | 0 | CHECK_MPI_OK(mp_init(&ar)); |
878 | | |
879 | 0 | SECITEM_TO_MPINT(ecParams->order, &n); |
880 | 0 | SECITEM_TO_MPINT(key->privateValue, &d); |
881 | | |
882 | 0 | CHECK_MPI_OK(mp_read_unsigned_octets(&k, kb, kblen)); |
883 | | /* Make sure k is in the interval [1, n-1] */ |
884 | 0 | if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) { |
885 | | #if EC_DEBUG |
886 | | printf("k is outside [1, n-1]\n"); |
887 | | mp_tohex(&k, mpstr); |
888 | | printf("k : %s \n", mpstr); |
889 | | mp_tohex(&n, mpstr); |
890 | | printf("n : %s \n", mpstr); |
891 | | #endif |
892 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
893 | 0 | goto cleanup; |
894 | 0 | } |
895 | | |
896 | | /* |
897 | | ** ANSI X9.62, Section 5.3.2, Step 2 |
898 | | ** |
899 | | ** Compute kG |
900 | | */ |
901 | 0 | kGpoint.len = EC_GetPointSize(ecParams); |
902 | 0 | kGpoint.data = PORT_Alloc(kGpoint.len); |
903 | 0 | if ((kGpoint.data == NULL) || |
904 | 0 | (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess)) |
905 | 0 | goto cleanup; |
906 | 0 | NSS_DECLASSIFY(kGpoint.data, kGpoint.len); /* Declassifying the r component */ |
907 | | /* |
908 | | ** ANSI X9.62, Section 5.3.3, Step 1 |
909 | | ** |
910 | | ** Extract the x co-ordinate of kG into x1 |
911 | | */ |
912 | 0 | CHECK_MPI_OK(mp_read_unsigned_octets(&x1, kGpoint.data + 1, |
913 | 0 | (mp_size)flen)); |
914 | | |
915 | | /* |
916 | | ** ANSI X9.62, Section 5.3.3, Step 2 |
917 | | ** |
918 | | ** r = x1 mod n NOTE: n is the order of the curve |
919 | | */ |
920 | 0 | CHECK_MPI_OK(mp_mod(&x1, &n, &r)); |
921 | | |
922 | | /* |
923 | | ** ANSI X9.62, Section 5.3.3, Step 3 |
924 | | ** |
925 | | ** verify r != 0 |
926 | | */ |
927 | 0 | if (mp_cmp_z(&r) == 0) { |
928 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
929 | 0 | goto cleanup; |
930 | 0 | } |
931 | | |
932 | | /* |
933 | | ** ANSI X9.62, Section 5.3.3, Step 4 |
934 | | ** |
935 | | ** s = (k**-1 * (HASH(M) + d*r)) mod n |
936 | | */ |
937 | 0 | SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */ |
938 | | |
939 | | /* In the definition of EC signing, digests are truncated |
940 | | * to the length of n in bits. |
941 | | * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ |
942 | 0 | CHECK_MPI_OK((obits = mpl_significant_bits(&n))); |
943 | 0 | if (digest->len * 8 > obits) { |
944 | 0 | mpl_rsh(&s, &s, digest->len * 8 - obits); |
945 | 0 | } |
946 | |
|
947 | | #if EC_DEBUG |
948 | | mp_todecimal(&n, mpstr); |
949 | | printf("n : %s (dec)\n", mpstr); |
950 | | mp_todecimal(&d, mpstr); |
951 | | printf("d : %s (dec)\n", mpstr); |
952 | | mp_tohex(&x1, mpstr); |
953 | | printf("x1: %s\n", mpstr); |
954 | | mp_todecimal(&s, mpstr); |
955 | | printf("digest: %s (decimal)\n", mpstr); |
956 | | mp_todecimal(&r, mpstr); |
957 | | printf("r : %s (dec)\n", mpstr); |
958 | | mp_tohex(&r, mpstr); |
959 | | printf("r : %s\n", mpstr); |
960 | | #endif |
961 | |
|
962 | 0 | if ((t2 = PORT_Alloc(2 * ecParams->order.len)) == NULL) { |
963 | 0 | rv = SECFailure; |
964 | 0 | goto cleanup; |
965 | 0 | } |
966 | 0 | if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) { |
967 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
968 | 0 | rv = SECFailure; |
969 | 0 | goto cleanup; |
970 | 0 | } |
971 | 0 | CHECK_MPI_OK(mp_read_unsigned_octets(&t, t2, 2 * ecParams->order.len)); /* t <-$ Zn */ |
972 | 0 | PORT_Memset(t2, 0, 2 * ecParams->order.len); |
973 | 0 | if (RNG_GenerateGlobalRandomBytes(t2, 2 * ecParams->order.len) != SECSuccess) { |
974 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
975 | 0 | rv = SECFailure; |
976 | 0 | goto cleanup; |
977 | 0 | } |
978 | 0 | CHECK_MPI_OK(mp_read_unsigned_octets(&ar, t2, 2 * ecParams->order.len)); /* ar <-$ Zn */ |
979 | | |
980 | | /* Using mp_invmod on k directly would leak bits from k. */ |
981 | 0 | CHECK_MPI_OK(mp_mul(&k, &ar, &k)); /* k = k * ar */ |
982 | 0 | NSS_DECLASSIFY(MP_DIGITS(&k), MP_ALLOC(&k) * sizeof(mp_digit)); /* declassifying k here because it is masked by multiplying with ar */ |
983 | 0 | CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */ |
984 | 0 | CHECK_MPI_OK(mp_invmod(&k, &n, &k)); /* k = k**-1 mod n */ |
985 | 0 | CHECK_MPI_OK(mp_mulmod(&k, &t, &n, &k)); /* k = k * t mod n */ |
986 | | /* To avoid leaking secret bits here the addition is blinded. */ |
987 | 0 | CHECK_MPI_OK(mp_mul(&d, &ar, &t)); /* t = d * ar */ |
988 | 0 | NSS_DECLASSIFY(MP_DIGITS(&t), MP_ALLOC(&t) * sizeof(mp_digit)); /* declassifying d here because it is masked by multiplying with ar */ |
989 | 0 | CHECK_MPI_OK(mp_mulmod(&t, &r, &n, &d)); /* d = t * r mod n */ |
990 | 0 | CHECK_MPI_OK(mp_mulmod(&s, &ar, &n, &t)); /* t = s * ar mod n */ |
991 | 0 | CHECK_MPI_OK(mp_add(&t, &d, &s)); /* s = t + d */ |
992 | 0 | CHECK_MPI_OK(mp_mulmod(&s, &k, &n, &s)); /* s = s * k mod n */ |
993 | | |
994 | | #if EC_DEBUG |
995 | | mp_todecimal(&s, mpstr); |
996 | | printf("s : %s (dec)\n", mpstr); |
997 | | mp_tohex(&s, mpstr); |
998 | | printf("s : %s\n", mpstr); |
999 | | #endif |
1000 | | |
1001 | | /* |
1002 | | ** ANSI X9.62, Section 5.3.3, Step 5 |
1003 | | ** |
1004 | | ** verify s != 0 |
1005 | | */ |
1006 | 0 | if (mp_cmp_z(&s) == 0) { |
1007 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
1008 | 0 | goto cleanup; |
1009 | 0 | } |
1010 | | |
1011 | | /* |
1012 | | ** |
1013 | | ** Signature is tuple (r, s) |
1014 | | */ |
1015 | 0 | CHECK_MPI_OK(mp_to_fixlen_octets(&r, signature->data, olen)); |
1016 | 0 | CHECK_MPI_OK(mp_to_fixlen_octets(&s, signature->data + olen, olen)); |
1017 | | |
1018 | 0 | signature->len = 2 * olen; |
1019 | 0 | rv = SECSuccess; |
1020 | 0 | err = MP_OKAY; |
1021 | |
|
1022 | 0 | cleanup: |
1023 | 0 | mp_clear(&x1); |
1024 | 0 | mp_clear(&d); |
1025 | 0 | mp_clear(&k); |
1026 | 0 | mp_clear(&r); |
1027 | 0 | mp_clear(&s); |
1028 | 0 | mp_clear(&n); |
1029 | 0 | mp_clear(&t); |
1030 | 0 | mp_clear(&ar); |
1031 | |
|
1032 | 0 | if (t2) { |
1033 | 0 | PORT_ZFree(t2, 2 * ecParams->order.len); |
1034 | 0 | } |
1035 | |
|
1036 | 0 | if (kGpoint.data) { |
1037 | 0 | PORT_ZFree(kGpoint.data, kGpoint.len); |
1038 | 0 | } |
1039 | |
|
1040 | 1.30k | done: |
1041 | 1.30k | if (err) { |
1042 | 0 | MP_TO_SEC_ERROR(err); |
1043 | 0 | rv = SECFailure; |
1044 | 0 | } |
1045 | | |
1046 | | #if EC_DEBUG |
1047 | | printf("ECDSA signing with seed %s\n", |
1048 | | (rv == SECSuccess) ? "succeeded" : "failed"); |
1049 | | #endif |
1050 | | |
1051 | 1.30k | return rv; |
1052 | 1.30k | } |
1053 | | |
1054 | | SECStatus |
1055 | | ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, |
1056 | | const SECItem *digest, const unsigned char *kb, const int kblen) |
1057 | 1.30k | { |
1058 | | #if EC_DEBUG || EC_DOUBLECHECK |
1059 | | SECItem *signature2 = SECITEM_AllocItem(NULL, NULL, signature->len); |
1060 | | SECStatus signSuccess = ec_SignDigestWithSeed(key, signature, digest, kb, kblen); |
1061 | | SECStatus signSuccessDouble = ec_SignDigestWithSeed(key, signature2, digest, kb, kblen); |
1062 | | int signaturesEqual = NSS_SecureMemcmp(signature->data, signature2->data, signature->len); |
1063 | | SECStatus rv; |
1064 | | |
1065 | | if ((signaturesEqual == 0) && (signSuccess == SECSuccess) && (signSuccessDouble == SECSuccess)) { |
1066 | | rv = SECSuccess; |
1067 | | } else { |
1068 | | rv = SECFailure; |
1069 | | } |
1070 | | |
1071 | | #if EC_DEBUG |
1072 | | printf("ECDSA signing with seed %s after signing twice\n", (rv == SECSuccess) ? "succeeded" : "failed"); |
1073 | | #endif |
1074 | | |
1075 | | SECITEM_FreeItem(signature2, PR_TRUE); |
1076 | | return rv; |
1077 | | #else |
1078 | 1.30k | return ec_SignDigestWithSeed(key, signature, digest, kb, kblen); |
1079 | 1.30k | #endif |
1080 | 1.30k | } |
1081 | | |
1082 | | /* |
1083 | | ** Computes the ECDSA signature on the digest using the given key |
1084 | | ** and a random seed. |
1085 | | */ |
1086 | | SECStatus |
1087 | | ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest) |
1088 | 1.30k | { |
1089 | 1.30k | SECStatus rv = SECFailure; |
1090 | 1.30k | SECItem nonceRand = { siBuffer, NULL, 0 }; |
1091 | | |
1092 | 1.30k | if (!key) { |
1093 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1094 | 0 | return SECFailure; |
1095 | 0 | } |
1096 | | |
1097 | | /* Generate random value k */ |
1098 | 1.30k | SECITEM_AllocItem(NULL, &nonceRand, EC_GetScalarSize(&key->ecParams)); |
1099 | 1.30k | if (nonceRand.data == NULL) { |
1100 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
1101 | 0 | rv = SECFailure; |
1102 | 0 | goto cleanup; |
1103 | 0 | } |
1104 | 1.30k | rv = ec_GenerateRandomPrivateKey(&key->ecParams, &nonceRand); |
1105 | 1.30k | if (rv != SECSuccess || nonceRand.data == NULL) |
1106 | 0 | goto cleanup; |
1107 | | |
1108 | | /* Generate ECDSA signature with the specified k value */ |
1109 | 1.30k | rv = ECDSA_SignDigestWithSeed(key, signature, digest, nonceRand.data, nonceRand.len); |
1110 | 1.30k | NSS_DECLASSIFY(signature->data, signature->len); |
1111 | | |
1112 | 1.30k | cleanup: |
1113 | 1.30k | if (nonceRand.data) { |
1114 | 1.30k | SECITEM_ZfreeItem(&nonceRand, PR_FALSE); |
1115 | 1.30k | } |
1116 | | |
1117 | | #if EC_DEBUG |
1118 | | printf("ECDSA signing %s\n", |
1119 | | (rv == SECSuccess) ? "succeeded" : "failed"); |
1120 | | #endif |
1121 | | |
1122 | 1.30k | return rv; |
1123 | 1.30k | } |
1124 | | |
1125 | | /* |
1126 | | ** Checks the signature on the given digest using the key provided. |
1127 | | ** |
1128 | | ** The key argument must represent a valid EC public key (a point on |
1129 | | ** the relevant curve). If it is not a valid point, then the behavior |
1130 | | ** of this function is undefined. In cases where a public key might |
1131 | | ** not be valid, use EC_ValidatePublicKey to check. |
1132 | | */ |
1133 | | SECStatus |
1134 | | ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, |
1135 | | const SECItem *digest) |
1136 | 1.37k | { |
1137 | 1.37k | SECStatus rv = SECFailure; |
1138 | 1.37k | ECParams *ecParams = NULL; |
1139 | 1.37k | mp_err err = MP_OKAY; |
1140 | | |
1141 | | /* Check args */ |
1142 | 1.37k | if (!key || !signature || !digest) { |
1143 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1144 | 0 | rv = SECFailure; |
1145 | 0 | goto done; |
1146 | 0 | } |
1147 | | |
1148 | 1.37k | ecParams = &(key->ecParams); |
1149 | | |
1150 | | /* Perform curve specific signature verification using ECMethod */ |
1151 | 1.37k | if (ecParams->fieldID.type == ec_field_plain) { |
1152 | 287 | const ECMethod *method = ec_get_method_from_name(ecParams->name); |
1153 | 287 | if (method == NULL || method->verify_digest == NULL) { |
1154 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
1155 | 0 | rv = SECFailure; |
1156 | 0 | goto done; |
1157 | 0 | } |
1158 | 287 | rv = method->verify_digest(key, signature, digest); |
1159 | 287 | if (rv != SECSuccess) { |
1160 | 287 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1161 | 287 | } |
1162 | 287 | goto done; |
1163 | 287 | } |
1164 | | |
1165 | 1.08k | mp_int r_, s_; /* tuple (r', s') is received signature) */ |
1166 | 1.08k | mp_int c, u1, u2, v; /* intermediate values used in verification */ |
1167 | 1.08k | mp_int x1; |
1168 | 1.08k | mp_int n; |
1169 | 1.08k | SECItem pointC = { siBuffer, NULL, 0 }; |
1170 | 1.08k | int slen; /* length in bytes of a half signature (r or s) */ |
1171 | 1.08k | int flen; /* length in bytes of the field size */ |
1172 | 1.08k | unsigned olen; /* length in bytes of the base point order */ |
1173 | 1.08k | unsigned obits; /* length in bits of the base point order */ |
1174 | | |
1175 | | #if EC_DEBUG |
1176 | | char mpstr[256]; |
1177 | | printf("ECDSA verification called\n"); |
1178 | | #endif |
1179 | | |
1180 | | /* Initialize MPI integers. */ |
1181 | | /* must happen before the first potential call to cleanup */ |
1182 | 1.08k | MP_DIGITS(&r_) = 0; |
1183 | 1.08k | MP_DIGITS(&s_) = 0; |
1184 | 1.08k | MP_DIGITS(&c) = 0; |
1185 | 1.08k | MP_DIGITS(&u1) = 0; |
1186 | 1.08k | MP_DIGITS(&u2) = 0; |
1187 | 1.08k | MP_DIGITS(&x1) = 0; |
1188 | 1.08k | MP_DIGITS(&v) = 0; |
1189 | 1.08k | MP_DIGITS(&n) = 0; |
1190 | | |
1191 | 1.08k | CHECK_MPI_OK(mp_init(&r_)); |
1192 | 1.08k | CHECK_MPI_OK(mp_init(&s_)); |
1193 | 1.08k | CHECK_MPI_OK(mp_init(&c)); |
1194 | 1.08k | CHECK_MPI_OK(mp_init(&u1)); |
1195 | 1.08k | CHECK_MPI_OK(mp_init(&u2)); |
1196 | 1.08k | CHECK_MPI_OK(mp_init(&x1)); |
1197 | 1.08k | CHECK_MPI_OK(mp_init(&v)); |
1198 | 1.08k | CHECK_MPI_OK(mp_init(&n)); |
1199 | | |
1200 | 1.08k | flen = (ecParams->fieldID.size + 7) >> 3; |
1201 | 1.08k | olen = ecParams->order.len; |
1202 | 1.08k | if (signature->len == 0 || signature->len % 2 != 0 || |
1203 | 1.08k | signature->len > 2 * olen) { |
1204 | 0 | PORT_SetError(SEC_ERROR_INPUT_LEN); |
1205 | 0 | goto cleanup; |
1206 | 0 | } |
1207 | 1.08k | slen = signature->len / 2; |
1208 | | |
1209 | | /* |
1210 | | * The incoming point has been verified in sftk_handlePublicKeyObject. |
1211 | | */ |
1212 | | |
1213 | 1.08k | SECITEM_AllocItem(NULL, &pointC, EC_GetPointSize(ecParams)); |
1214 | 1.08k | if (pointC.data == NULL) { |
1215 | 0 | goto cleanup; |
1216 | 0 | } |
1217 | | |
1218 | | /* |
1219 | | ** Convert received signature (r', s') into MPI integers. |
1220 | | */ |
1221 | 1.08k | CHECK_MPI_OK(mp_read_unsigned_octets(&r_, signature->data, slen)); |
1222 | 1.08k | CHECK_MPI_OK(mp_read_unsigned_octets(&s_, signature->data + slen, slen)); |
1223 | | |
1224 | | /* |
1225 | | ** ANSI X9.62, Section 5.4.2, Steps 1 and 2 |
1226 | | ** |
1227 | | ** Verify that 0 < r' < n and 0 < s' < n |
1228 | | */ |
1229 | 1.08k | SECITEM_TO_MPINT(ecParams->order, &n); |
1230 | 1.08k | if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || |
1231 | 1.08k | mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) { |
1232 | 9 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1233 | 9 | goto cleanup; /* will return rv == SECFailure */ |
1234 | 9 | } |
1235 | | |
1236 | | /* |
1237 | | ** ANSI X9.62, Section 5.4.2, Step 3 |
1238 | | ** |
1239 | | ** c = (s')**-1 mod n |
1240 | | */ |
1241 | 1.07k | CHECK_MPI_OK(mp_invmod(&s_, &n, &c)); /* c = (s')**-1 mod n */ |
1242 | | |
1243 | | /* |
1244 | | ** ANSI X9.62, Section 5.4.2, Step 4 |
1245 | | ** |
1246 | | ** u1 = ((HASH(M')) * c) mod n |
1247 | | */ |
1248 | 1.07k | SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */ |
1249 | | |
1250 | | /* In the definition of EC signing, digests are truncated |
1251 | | * to the length of n in bits. |
1252 | | * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ |
1253 | 1.07k | CHECK_MPI_OK((obits = mpl_significant_bits(&n))); |
1254 | 1.07k | if (digest->len * 8 > obits) { /* u1 = HASH(M') */ |
1255 | 126 | mpl_rsh(&u1, &u1, digest->len * 8 - obits); |
1256 | 126 | } |
1257 | | |
1258 | | #if EC_DEBUG |
1259 | | mp_todecimal(&r_, mpstr); |
1260 | | printf("r_: %s (dec)\n", mpstr); |
1261 | | mp_todecimal(&s_, mpstr); |
1262 | | printf("s_: %s (dec)\n", mpstr); |
1263 | | mp_todecimal(&c, mpstr); |
1264 | | printf("c : %s (dec)\n", mpstr); |
1265 | | mp_todecimal(&u1, mpstr); |
1266 | | printf("digest: %s (dec)\n", mpstr); |
1267 | | #endif |
1268 | | |
1269 | 1.07k | CHECK_MPI_OK(mp_mulmod(&u1, &c, &n, &u1)); /* u1 = u1 * c mod n */ |
1270 | | |
1271 | | /* |
1272 | | ** ANSI X9.62, Section 5.4.2, Step 4 |
1273 | | ** |
1274 | | ** u2 = ((r') * c) mod n |
1275 | | */ |
1276 | 1.07k | CHECK_MPI_OK(mp_mulmod(&r_, &c, &n, &u2)); |
1277 | | |
1278 | | /* |
1279 | | ** ANSI X9.62, Section 5.4.3, Step 1 |
1280 | | ** |
1281 | | ** Compute u1*G + u2*Q |
1282 | | ** Here, A = u1.G B = u2.Q and C = A + B |
1283 | | ** If the result, C, is the point at infinity, reject the signature |
1284 | | */ |
1285 | 1.07k | if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) != SECSuccess) { |
1286 | 0 | rv = SECFailure; |
1287 | 0 | goto cleanup; |
1288 | 0 | } |
1289 | 1.07k | if (ec_point_at_infinity(&pointC)) { |
1290 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1291 | 0 | rv = SECFailure; |
1292 | 0 | goto cleanup; |
1293 | 0 | } |
1294 | | |
1295 | 1.07k | CHECK_MPI_OK(mp_read_unsigned_octets(&x1, pointC.data + 1, flen)); |
1296 | | |
1297 | | /* |
1298 | | ** ANSI X9.62, Section 5.4.4, Step 2 |
1299 | | ** |
1300 | | ** v = x1 mod n |
1301 | | */ |
1302 | 1.07k | CHECK_MPI_OK(mp_mod(&x1, &n, &v)); |
1303 | | |
1304 | | #if EC_DEBUG |
1305 | | mp_todecimal(&r_, mpstr); |
1306 | | printf("r_: %s (dec)\n", mpstr); |
1307 | | mp_todecimal(&v, mpstr); |
1308 | | printf("v : %s (dec)\n", mpstr); |
1309 | | #endif |
1310 | | |
1311 | | /* |
1312 | | ** ANSI X9.62, Section 5.4.4, Step 3 |
1313 | | ** |
1314 | | ** Verification: v == r' |
1315 | | */ |
1316 | 1.07k | if (mp_cmp(&v, &r_)) { |
1317 | 1.07k | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1318 | 1.07k | rv = SECFailure; /* Signature failed to verify. */ |
1319 | 1.07k | } else { |
1320 | 0 | rv = SECSuccess; /* Signature verified. */ |
1321 | 0 | } |
1322 | | |
1323 | | #if EC_DEBUG |
1324 | | mp_todecimal(&u1, mpstr); |
1325 | | printf("u1: %s (dec)\n", mpstr); |
1326 | | mp_todecimal(&u2, mpstr); |
1327 | | printf("u2: %s (dec)\n", mpstr); |
1328 | | mp_tohex(&x1, mpstr); |
1329 | | printf("x1: %s\n", mpstr); |
1330 | | mp_todecimal(&v, mpstr); |
1331 | | printf("v : %s (dec)\n", mpstr); |
1332 | | #endif |
1333 | | |
1334 | 1.08k | cleanup: |
1335 | 1.08k | mp_clear(&r_); |
1336 | 1.08k | mp_clear(&s_); |
1337 | 1.08k | mp_clear(&c); |
1338 | 1.08k | mp_clear(&u1); |
1339 | 1.08k | mp_clear(&u2); |
1340 | 1.08k | mp_clear(&x1); |
1341 | 1.08k | mp_clear(&v); |
1342 | 1.08k | mp_clear(&n); |
1343 | | |
1344 | 1.08k | if (pointC.data) |
1345 | 1.08k | SECITEM_ZfreeItem(&pointC, PR_FALSE); |
1346 | | |
1347 | 1.37k | done: |
1348 | 1.37k | if (err) { |
1349 | 0 | MP_TO_SEC_ERROR(err); |
1350 | 0 | rv = SECFailure; |
1351 | 0 | } |
1352 | | |
1353 | | #if EC_DEBUG |
1354 | | printf("ECDSA verification %s\n", |
1355 | | (rv == SECSuccess) ? "succeeded" : "failed"); |
1356 | | #endif |
1357 | | |
1358 | 1.37k | return rv; |
1359 | 1.37k | } |
1360 | | |
1361 | | /*EdDSA: Currently only Ed22519 is implemented.*/ |
1362 | | |
1363 | | /* |
1364 | | ** Computes the EdDSA signature on the message using the given key. |
1365 | | */ |
1366 | | |
1367 | | SECStatus |
1368 | | ec_ED25519_public_key_validate(const ECPublicKey *key) |
1369 | 0 | { |
1370 | 0 | if (!key || !(key->ecParams.name == ECCurve_Ed25519)) { |
1371 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1372 | 0 | return SECFailure; |
1373 | 0 | } |
1374 | 0 | return ec_ED25519_pt_validate(&key->publicValue); |
1375 | 0 | } |
1376 | | |
1377 | | SECStatus |
1378 | | ec_ED25519_private_key_validate(const ECPrivateKey *key) |
1379 | 0 | { |
1380 | 0 | if (!key || !(key->ecParams.name == ECCurve_Ed25519)) { |
1381 | |
|
1382 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1383 | 0 | return SECFailure; |
1384 | 0 | } |
1385 | 0 | return ec_ED25519_scalar_validate(&key->privateValue); |
1386 | 0 | } |
1387 | | |
1388 | | SECStatus |
1389 | | ED_SignMessage(ECPrivateKey *key, SECItem *signature, const SECItem *msg) |
1390 | 0 | { |
1391 | 0 | if (!msg || !signature || signature->len != Ed25519_SIGN_LEN) { |
1392 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1393 | 0 | return SECFailure; |
1394 | 0 | } |
1395 | | |
1396 | 0 | if (ec_ED25519_private_key_validate(key) != SECSuccess) { |
1397 | 0 | return SECFailure; /* error code set by ec_ED25519_scalar_validate. */ |
1398 | 0 | } |
1399 | | |
1400 | 0 | if (signature->data) { |
1401 | 0 | Hacl_Ed25519_sign(signature->data, key->privateValue.data, msg->len, |
1402 | 0 | msg->data); |
1403 | 0 | } |
1404 | 0 | signature->len = ED25519_SIGN_LEN; |
1405 | 0 | BLAPI_CLEAR_STACK(2048); |
1406 | 0 | return SECSuccess; |
1407 | 0 | } |
1408 | | |
1409 | | /* |
1410 | | ** Checks the signature on the given message using the key provided. |
1411 | | */ |
1412 | | |
1413 | | SECStatus |
1414 | | ED_VerifyMessage(ECPublicKey *key, const SECItem *signature, |
1415 | | const SECItem *msg) |
1416 | 0 | { |
1417 | 0 | if (!msg || !signature || !signature->data || signature->len != Ed25519_SIGN_LEN) { |
1418 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1419 | 0 | return SECFailure; |
1420 | 0 | } |
1421 | | |
1422 | 0 | if (ec_ED25519_public_key_validate(key) != SECSuccess) { |
1423 | 0 | return SECFailure; /* error code set by ec_ED25519_pt_validate. */ |
1424 | 0 | } |
1425 | | |
1426 | 0 | bool rv = Hacl_Ed25519_verify(key->publicValue.data, msg->len, msg->data, |
1427 | 0 | signature->data); |
1428 | 0 | BLAPI_CLEAR_STACK(2048); |
1429 | |
|
1430 | | #if EC_DEBUG |
1431 | | printf("ED_VerifyMessage returning %s\n", |
1432 | | (rv) ? "success" : "failure"); |
1433 | | #endif |
1434 | |
|
1435 | 0 | if (rv) { |
1436 | 0 | return SECSuccess; |
1437 | 0 | } |
1438 | | |
1439 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1440 | 0 | return SECFailure; |
1441 | 0 | } |
1442 | | |
1443 | | SECStatus |
1444 | | ED_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey) |
1445 | 0 | { |
1446 | | /* Currently supporting only Ed25519.*/ |
1447 | 0 | if (!privateKey || privateKey->len == 0 || !publicKey || publicKey->len != Ed25519_PUBLIC_KEYLEN) { |
1448 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1449 | 0 | return SECFailure; |
1450 | 0 | } |
1451 | | |
1452 | 0 | if (ec_ED25519_scalar_validate(privateKey) != SECSuccess) { |
1453 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1454 | 0 | return SECFailure; |
1455 | 0 | } |
1456 | | |
1457 | 0 | Hacl_Ed25519_secret_to_public(publicKey->data, privateKey->data); |
1458 | 0 | return SECSuccess; |
1459 | 0 | } |