/src/nss/lib/freebl/dsa.c
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifdef FREEBL_NO_DEPEND |
8 | | #include "stubs.h" |
9 | | #endif |
10 | | |
11 | | #include "prerror.h" |
12 | | #include "secerr.h" |
13 | | |
14 | | #include "prtypes.h" |
15 | | #include "prinit.h" |
16 | | #include "blapi.h" |
17 | | #include "secitem.h" |
18 | | #include "blapit.h" |
19 | | #include "mpi.h" |
20 | | #include "secmpi.h" |
21 | | #include "pqg.h" |
22 | | |
23 | | /* |
24 | | * FIPS 186-2 requires result from random output to be reduced mod q when |
25 | | * generating random numbers for DSA. |
26 | | * |
27 | | * Input: w, 2*qLen bytes |
28 | | * q, qLen bytes |
29 | | * Output: xj, qLen bytes |
30 | | */ |
31 | | static SECStatus |
32 | | fips186Change_ReduceModQForDSA(const PRUint8 *w, const PRUint8 *q, |
33 | | unsigned int qLen, PRUint8 *xj) |
34 | 0 | { |
35 | 0 | mp_int W, Q, Xj; |
36 | 0 | mp_err err; |
37 | 0 | SECStatus rv = SECSuccess; |
38 | | |
39 | | /* Initialize MPI integers. */ |
40 | 0 | MP_DIGITS(&W) = 0; |
41 | 0 | MP_DIGITS(&Q) = 0; |
42 | 0 | MP_DIGITS(&Xj) = 0; |
43 | 0 | CHECK_MPI_OK(mp_init(&W)); |
44 | 0 | CHECK_MPI_OK(mp_init(&Q)); |
45 | 0 | CHECK_MPI_OK(mp_init(&Xj)); |
46 | | /* |
47 | | * Convert input arguments into MPI integers. |
48 | | */ |
49 | 0 | CHECK_MPI_OK(mp_read_unsigned_octets(&W, w, 2 * qLen)); |
50 | 0 | CHECK_MPI_OK(mp_read_unsigned_octets(&Q, q, qLen)); |
51 | | |
52 | | /* |
53 | | * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3 |
54 | | * |
55 | | * xj = (w0 || w1) mod q |
56 | | */ |
57 | 0 | CHECK_MPI_OK(mp_mod(&W, &Q, &Xj)); |
58 | 0 | CHECK_MPI_OK(mp_to_fixlen_octets(&Xj, xj, qLen)); |
59 | 0 | cleanup: |
60 | 0 | mp_clear(&W); |
61 | 0 | mp_clear(&Q); |
62 | 0 | mp_clear(&Xj); |
63 | 0 | if (err) { |
64 | 0 | MP_TO_SEC_ERROR(err); |
65 | 0 | rv = SECFailure; |
66 | 0 | } |
67 | 0 | return rv; |
68 | 0 | } |
69 | | |
70 | | /* |
71 | | * FIPS 186-2 requires result from random output to be reduced mod q when |
72 | | * generating random numbers for DSA. |
73 | | */ |
74 | | SECStatus |
75 | | FIPS186Change_ReduceModQForDSA(const unsigned char *w, |
76 | | const unsigned char *q, |
77 | | unsigned char *xj) |
78 | 0 | { |
79 | 0 | return fips186Change_ReduceModQForDSA(w, q, DSA1_SUBPRIME_LEN, xj); |
80 | 0 | } |
81 | | |
82 | | /* |
83 | | * The core of Algorithm 1 of FIPS 186-2 Change Notice 1. |
84 | | * |
85 | | * We no longer support FIPS 186-2 RNG. This function was exported |
86 | | * for power-up self tests and FIPS tests. Keep this stub, which fails, |
87 | | * to prevent crashes, but also to signal to test code that FIPS 186-2 |
88 | | * RNG is no longer supported. |
89 | | */ |
90 | | SECStatus |
91 | | FIPS186Change_GenerateX(PRUint8 *XKEY, const PRUint8 *XSEEDj, |
92 | | PRUint8 *x_j) |
93 | 0 | { |
94 | 0 | PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); |
95 | 0 | return SECFailure; |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * Specialized RNG for DSA |
100 | | * |
101 | | * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value |
102 | | * Xj should be reduced mod q, a 160-bit prime number. Since this parameter |
103 | | * is only meaningful in the context of DSA, the above RNG functions |
104 | | * were implemented without it. They are re-implemented below for use |
105 | | * with DSA. |
106 | | */ |
107 | | |
108 | | /* |
109 | | ** Generate some random bytes, using the global random number generator |
110 | | ** object. In DSA mode, so there is a q. |
111 | | */ |
112 | | static SECStatus |
113 | | dsa_GenerateGlobalRandomBytes(const SECItem *qItem, PRUint8 *dest, |
114 | | unsigned int *destLen, unsigned int maxDestLen) |
115 | 0 | { |
116 | 0 | SECStatus rv; |
117 | 0 | SECItem w; |
118 | 0 | const PRUint8 *q = qItem->data; |
119 | 0 | unsigned int qLen = qItem->len; |
120 | |
|
121 | 0 | if (*q == 0) { |
122 | 0 | ++q; |
123 | 0 | --qLen; |
124 | 0 | } |
125 | 0 | if (maxDestLen < qLen) { |
126 | | /* This condition can occur when DSA_SignDigest is passed a group |
127 | | with a subprime that is larger than DSA_MAX_SUBPRIME_LEN. */ |
128 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
129 | 0 | return SECFailure; |
130 | 0 | } |
131 | 0 | w.data = NULL; /* otherwise SECITEM_AllocItem asserts */ |
132 | 0 | if (!SECITEM_AllocItem(NULL, &w, 2 * qLen)) { |
133 | 0 | return SECFailure; |
134 | 0 | } |
135 | 0 | *destLen = qLen; |
136 | |
|
137 | 0 | rv = RNG_GenerateGlobalRandomBytes(w.data, w.len); |
138 | 0 | if (rv == SECSuccess) { |
139 | 0 | rv = fips186Change_ReduceModQForDSA(w.data, q, qLen, dest); |
140 | 0 | } |
141 | |
|
142 | 0 | SECITEM_FreeItem(&w, PR_FALSE); |
143 | 0 | return rv; |
144 | 0 | } |
145 | | |
146 | | static void |
147 | | translate_mpi_error(mp_err err) |
148 | 293 | { |
149 | 293 | MP_TO_SEC_ERROR(err); |
150 | 293 | } |
151 | | |
152 | | static SECStatus |
153 | | dsa_NewKeyExtended(const PQGParams *params, const SECItem *seed, |
154 | | DSAPrivateKey **privKey) |
155 | 0 | { |
156 | 0 | mp_int p, g; |
157 | 0 | mp_int x, y; |
158 | 0 | mp_err err; |
159 | 0 | PLArenaPool *arena; |
160 | 0 | DSAPrivateKey *key; |
161 | | /* Check args. */ |
162 | 0 | if (!params || !privKey || !seed || !seed->data) { |
163 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
164 | 0 | return SECFailure; |
165 | 0 | } |
166 | | /* Initialize an arena for the DSA key. */ |
167 | 0 | arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); |
168 | 0 | if (!arena) { |
169 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
170 | 0 | return SECFailure; |
171 | 0 | } |
172 | 0 | key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey)); |
173 | 0 | if (!key) { |
174 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
175 | 0 | PORT_FreeArena(arena, PR_TRUE); |
176 | 0 | return SECFailure; |
177 | 0 | } |
178 | 0 | key->params.arena = arena; |
179 | | /* Initialize MPI integers. */ |
180 | 0 | MP_DIGITS(&p) = 0; |
181 | 0 | MP_DIGITS(&g) = 0; |
182 | 0 | MP_DIGITS(&x) = 0; |
183 | 0 | MP_DIGITS(&y) = 0; |
184 | 0 | CHECK_MPI_OK(mp_init(&p)); |
185 | 0 | CHECK_MPI_OK(mp_init(&g)); |
186 | 0 | CHECK_MPI_OK(mp_init(&x)); |
187 | 0 | CHECK_MPI_OK(mp_init(&y)); |
188 | | /* Copy over the PQG params */ |
189 | 0 | CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.prime, |
190 | 0 | ¶ms->prime)); |
191 | 0 | CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.subPrime, |
192 | 0 | ¶ms->subPrime)); |
193 | 0 | CHECK_MPI_OK(SECITEM_CopyItem(arena, &key->params.base, ¶ms->base)); |
194 | | /* Convert stored p, g, and received x into MPI integers. */ |
195 | 0 | SECITEM_TO_MPINT(params->prime, &p); |
196 | 0 | SECITEM_TO_MPINT(params->base, &g); |
197 | 0 | OCTETS_TO_MPINT(seed->data, &x, seed->len); |
198 | | /* Store x in private key */ |
199 | 0 | SECITEM_AllocItem(arena, &key->privateValue, seed->len); |
200 | 0 | PORT_Memcpy(key->privateValue.data, seed->data, seed->len); |
201 | | /* Compute public key y = g**x mod p */ |
202 | 0 | CHECK_MPI_OK(mp_exptmod(&g, &x, &p, &y)); |
203 | | /* Store y in public key */ |
204 | 0 | MPINT_TO_SECITEM(&y, &key->publicValue, arena); |
205 | 0 | *privKey = key; |
206 | 0 | key = NULL; |
207 | 0 | cleanup: |
208 | 0 | mp_clear(&p); |
209 | 0 | mp_clear(&g); |
210 | 0 | mp_clear(&x); |
211 | 0 | mp_clear(&y); |
212 | 0 | if (key) { |
213 | 0 | PORT_FreeArena(key->params.arena, PR_TRUE); |
214 | 0 | } |
215 | 0 | if (err) { |
216 | 0 | translate_mpi_error(err); |
217 | 0 | return SECFailure; |
218 | 0 | } |
219 | 0 | return SECSuccess; |
220 | 0 | } |
221 | | |
222 | | SECStatus |
223 | | DSA_NewRandom(PLArenaPool *arena, const SECItem *q, SECItem *seed) |
224 | 0 | { |
225 | 0 | int retries = 10; |
226 | 0 | unsigned int i; |
227 | 0 | PRBool good; |
228 | |
|
229 | 0 | if (q == NULL || q->data == NULL || q->len == 0 || |
230 | 0 | (q->data[0] == 0 && q->len == 1)) { |
231 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
232 | 0 | return SECFailure; |
233 | 0 | } |
234 | | |
235 | 0 | if (!SECITEM_AllocItem(arena, seed, q->len)) { |
236 | 0 | return SECFailure; |
237 | 0 | } |
238 | | |
239 | 0 | do { |
240 | | /* Generate seed bytes for x according to FIPS 186-1 appendix 3 */ |
241 | 0 | if (dsa_GenerateGlobalRandomBytes(q, seed->data, &seed->len, |
242 | 0 | seed->len)) { |
243 | 0 | goto loser; |
244 | 0 | } |
245 | | /* Disallow values of 0 and 1 for x. */ |
246 | 0 | good = PR_FALSE; |
247 | 0 | for (i = 0; i < seed->len - 1; i++) { |
248 | 0 | if (seed->data[i] != 0) { |
249 | 0 | good = PR_TRUE; |
250 | 0 | break; |
251 | 0 | } |
252 | 0 | } |
253 | 0 | if (!good && seed->data[i] > 1) { |
254 | 0 | good = PR_TRUE; |
255 | 0 | } |
256 | 0 | } while (!good && --retries > 0); |
257 | | |
258 | 0 | if (!good) { |
259 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
260 | 0 | loser: |
261 | 0 | if (arena == NULL) { |
262 | 0 | SECITEM_ZfreeItem(seed, PR_FALSE); |
263 | 0 | } |
264 | 0 | return SECFailure; |
265 | 0 | } |
266 | | |
267 | 0 | return SECSuccess; |
268 | 0 | } |
269 | | |
270 | | /* |
271 | | ** Generate and return a new DSA public and private key pair, |
272 | | ** both of which are encoded into a single DSAPrivateKey struct. |
273 | | ** "params" is a pointer to the PQG parameters for the domain |
274 | | ** Uses a random seed. |
275 | | */ |
276 | | SECStatus |
277 | | DSA_NewKey(const PQGParams *params, DSAPrivateKey **privKey) |
278 | 0 | { |
279 | 0 | SECItem seed; |
280 | 0 | SECStatus rv; |
281 | |
|
282 | 0 | rv = PQG_Check(params); |
283 | 0 | if (rv != SECSuccess) { |
284 | 0 | return rv; |
285 | 0 | } |
286 | 0 | seed.data = NULL; |
287 | |
|
288 | 0 | rv = DSA_NewRandom(NULL, ¶ms->subPrime, &seed); |
289 | 0 | if (rv == SECSuccess) { |
290 | 0 | if (seed.len != PQG_GetLength(¶ms->subPrime)) { |
291 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
292 | 0 | rv = SECFailure; |
293 | 0 | } else { |
294 | 0 | rv = dsa_NewKeyExtended(params, &seed, privKey); |
295 | 0 | } |
296 | 0 | } |
297 | 0 | SECITEM_ZfreeItem(&seed, PR_FALSE); |
298 | 0 | return rv; |
299 | 0 | } |
300 | | |
301 | | /* For FIPS compliance testing. Seed must be exactly the size of subPrime */ |
302 | | SECStatus |
303 | | DSA_NewKeyFromSeed(const PQGParams *params, |
304 | | const unsigned char *seed, |
305 | | DSAPrivateKey **privKey) |
306 | 0 | { |
307 | 0 | SECItem seedItem; |
308 | 0 | seedItem.data = (unsigned char *)seed; |
309 | 0 | seedItem.len = PQG_GetLength(¶ms->subPrime); |
310 | 0 | return dsa_NewKeyExtended(params, &seedItem, privKey); |
311 | 0 | } |
312 | | |
313 | | static SECStatus |
314 | | dsa_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest, |
315 | | const unsigned char *kbytes) |
316 | 0 | { |
317 | 0 | mp_int p, q, g; /* PQG parameters */ |
318 | 0 | mp_int x, k; /* private key & pseudo-random integer */ |
319 | 0 | mp_int r, s; /* tuple (r, s) is signature) */ |
320 | 0 | mp_int t; /* holding tmp values */ |
321 | 0 | mp_int ar; /* holding blinding values */ |
322 | 0 | mp_digit fuzz; /* blinding multiplier for q */ |
323 | 0 | mp_err err = MP_OKAY; |
324 | 0 | SECStatus rv = SECSuccess; |
325 | 0 | unsigned int dsa_subprime_len, dsa_signature_len, offset; |
326 | 0 | SECItem localDigest; |
327 | 0 | unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; |
328 | 0 | SECItem t2 = { siBuffer, NULL, 0 }; |
329 | | |
330 | | /* FIPS-compliance dictates that digest is a SHA hash. */ |
331 | | /* Check args. */ |
332 | 0 | if (!key || !signature || !digest) { |
333 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
334 | 0 | return SECFailure; |
335 | 0 | } |
336 | | |
337 | 0 | dsa_subprime_len = PQG_GetLength(&key->params.subPrime); |
338 | 0 | dsa_signature_len = dsa_subprime_len * 2; |
339 | 0 | if ((dsa_subprime_len == 0) || |
340 | 0 | (dsa_subprime_len > DSA_MAX_SUBPRIME_LEN) || |
341 | 0 | (signature->len < dsa_signature_len) || |
342 | 0 | (digest->len > HASH_LENGTH_MAX) || |
343 | 0 | (digest->len < SHA1_LENGTH)) { |
344 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
345 | 0 | return SECFailure; |
346 | 0 | } |
347 | | |
348 | | /* DSA accepts digests not equal to dsa_subprime_len, if the |
349 | | * digests are greater, then they are truncated to the size of |
350 | | * dsa_subprime_len, using the left most bits. If they are less |
351 | | * then they are padded on the left.*/ |
352 | 0 | PORT_Memset(localDigestData, 0, dsa_subprime_len); |
353 | 0 | offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0; |
354 | 0 | PORT_Memcpy(localDigestData + offset, digest->data, |
355 | 0 | dsa_subprime_len - offset); |
356 | 0 | localDigest.data = localDigestData; |
357 | 0 | localDigest.len = dsa_subprime_len; |
358 | | |
359 | | /* Initialize MPI integers. */ |
360 | 0 | MP_DIGITS(&p) = 0; |
361 | 0 | MP_DIGITS(&q) = 0; |
362 | 0 | MP_DIGITS(&g) = 0; |
363 | 0 | MP_DIGITS(&x) = 0; |
364 | 0 | MP_DIGITS(&k) = 0; |
365 | 0 | MP_DIGITS(&r) = 0; |
366 | 0 | MP_DIGITS(&s) = 0; |
367 | 0 | MP_DIGITS(&t) = 0; |
368 | 0 | MP_DIGITS(&ar) = 0; |
369 | 0 | CHECK_MPI_OK(mp_init(&p)); |
370 | 0 | CHECK_MPI_OK(mp_init(&q)); |
371 | 0 | CHECK_MPI_OK(mp_init(&g)); |
372 | 0 | CHECK_MPI_OK(mp_init(&x)); |
373 | 0 | CHECK_MPI_OK(mp_init(&k)); |
374 | 0 | CHECK_MPI_OK(mp_init(&r)); |
375 | 0 | CHECK_MPI_OK(mp_init(&s)); |
376 | 0 | CHECK_MPI_OK(mp_init(&t)); |
377 | 0 | CHECK_MPI_OK(mp_init(&ar)); |
378 | | |
379 | | /* |
380 | | ** Convert stored PQG and private key into MPI integers. |
381 | | */ |
382 | 0 | SECITEM_TO_MPINT(key->params.prime, &p); |
383 | 0 | SECITEM_TO_MPINT(key->params.subPrime, &q); |
384 | 0 | SECITEM_TO_MPINT(key->params.base, &g); |
385 | 0 | SECITEM_TO_MPINT(key->privateValue, &x); |
386 | 0 | OCTETS_TO_MPINT(kbytes, &k, dsa_subprime_len); |
387 | | |
388 | | /* k blinding create a single value that has the high bit set in |
389 | | * the mp_digit*/ |
390 | 0 | if (RNG_GenerateGlobalRandomBytes(&fuzz, sizeof(mp_digit)) != SECSuccess) { |
391 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
392 | 0 | rv = SECFailure; |
393 | 0 | goto cleanup; |
394 | 0 | } |
395 | 0 | fuzz |= 1ULL << ((sizeof(mp_digit) * PR_BITS_PER_BYTE - 1)); |
396 | | /* |
397 | | ** FIPS 186-1, Section 5, Step 1 |
398 | | ** |
399 | | ** r = (g**k mod p) mod q |
400 | | */ |
401 | 0 | CHECK_MPI_OK(mp_mul_d(&q, fuzz, &t)); /* t = q*fuzz */ |
402 | 0 | CHECK_MPI_OK(mp_add(&k, &t, &t)); /* t = k+q*fuzz */ |
403 | | /* length of t is now fixed, bits in k have been blinded */ |
404 | 0 | CHECK_MPI_OK(mp_exptmod(&g, &t, &p, &r)); /* r = g**t mod p */ |
405 | | /* r is now g**(k+q*fuzz) == g**k mod p */ |
406 | 0 | CHECK_MPI_OK(mp_mod(&r, &q, &r)); /* r = r mod q */ |
407 | | /* make sure fuzz is cleared off the stack and not optimized away */ |
408 | 0 | *(volatile mp_digit *)&fuzz = 0; |
409 | | |
410 | | /* |
411 | | ** FIPS 186-1, Section 5, Step 2 |
412 | | ** |
413 | | ** s = (k**-1 * (HASH(M) + x*r)) mod q |
414 | | */ |
415 | 0 | if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) { |
416 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
417 | 0 | rv = SECFailure; |
418 | 0 | goto cleanup; |
419 | 0 | } |
420 | 0 | SECITEM_TO_MPINT(t2, &t); /* t <-$ Zq */ |
421 | 0 | SECITEM_ZfreeItem(&t2, PR_FALSE); |
422 | 0 | if (DSA_NewRandom(NULL, &key->params.subPrime, &t2) != SECSuccess) { |
423 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
424 | 0 | rv = SECFailure; |
425 | 0 | goto cleanup; |
426 | 0 | } |
427 | 0 | SECITEM_TO_MPINT(t2, &ar); /* ar <-$ Zq */ |
428 | 0 | SECITEM_ZfreeItem(&t2, PR_FALSE); |
429 | | |
430 | | /* Using mp_invmod on k directly would leak bits from k. */ |
431 | 0 | CHECK_MPI_OK(mp_mul(&k, &ar, &k)); /* k = k * ar */ |
432 | 0 | CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */ |
433 | | /* k is now k*t*ar */ |
434 | 0 | CHECK_MPI_OK(mp_invmod(&k, &q, &k)); /* k = k**-1 mod q */ |
435 | | /* k is now (k*t*ar)**-1 */ |
436 | 0 | CHECK_MPI_OK(mp_mulmod(&k, &t, &q, &k)); /* k = k * t mod q */ |
437 | | /* k is now (k*ar)**-1 */ |
438 | 0 | SECITEM_TO_MPINT(localDigest, &s); /* s = HASH(M) */ |
439 | | /* To avoid leaking secret bits here the addition is blinded. */ |
440 | 0 | CHECK_MPI_OK(mp_mul(&x, &ar, &x)); /* x = x * ar */ |
441 | | /* x is now x*ar */ |
442 | 0 | CHECK_MPI_OK(mp_mulmod(&x, &r, &q, &x)); /* x = x * r mod q */ |
443 | | /* x is now x*r*ar */ |
444 | 0 | CHECK_MPI_OK(mp_mulmod(&s, &ar, &q, &t)); /* t = s * ar mod q */ |
445 | | /* t is now hash(M)*ar */ |
446 | 0 | CHECK_MPI_OK(mp_add(&t, &x, &s)); /* s = t + x */ |
447 | | /* s is now (HASH(M)+x*r)*ar */ |
448 | 0 | CHECK_MPI_OK(mp_mulmod(&s, &k, &q, &s)); /* s = s * k mod q */ |
449 | | /* s is now (HASH(M)+x*r)*ar*(k*ar)**-1 = (k**-1)*(HASH(M)+x*r) */ |
450 | | |
451 | | /* |
452 | | ** verify r != 0 and s != 0 |
453 | | ** mentioned as optional in FIPS 186-1. |
454 | | */ |
455 | 0 | if (mp_cmp_z(&r) == 0 || mp_cmp_z(&s) == 0) { |
456 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
457 | 0 | rv = SECFailure; |
458 | 0 | goto cleanup; |
459 | 0 | } |
460 | | /* |
461 | | ** Step 4 |
462 | | ** |
463 | | ** Signature is tuple (r, s) |
464 | | */ |
465 | 0 | err = mp_to_fixlen_octets(&r, signature->data, dsa_subprime_len); |
466 | 0 | if (err < 0) |
467 | 0 | goto cleanup; |
468 | 0 | err = mp_to_fixlen_octets(&s, signature->data + dsa_subprime_len, |
469 | 0 | dsa_subprime_len); |
470 | 0 | if (err < 0) |
471 | 0 | goto cleanup; |
472 | 0 | err = MP_OKAY; |
473 | 0 | signature->len = dsa_signature_len; |
474 | 0 | cleanup: |
475 | 0 | PORT_SafeZero(localDigestData, DSA_MAX_SUBPRIME_LEN); |
476 | 0 | mp_clear(&p); |
477 | 0 | mp_clear(&q); |
478 | 0 | mp_clear(&g); |
479 | 0 | mp_clear(&x); |
480 | 0 | mp_clear(&k); |
481 | 0 | mp_clear(&r); |
482 | 0 | mp_clear(&s); |
483 | 0 | mp_clear(&t); |
484 | 0 | mp_clear(&ar); |
485 | 0 | if (err) { |
486 | 0 | translate_mpi_error(err); |
487 | 0 | rv = SECFailure; |
488 | 0 | } |
489 | 0 | return rv; |
490 | 0 | } |
491 | | |
492 | | /* signature is caller-supplied buffer of at least 40 bytes. |
493 | | ** On input, signature->len == size of buffer to hold signature. |
494 | | ** digest->len == size of digest. |
495 | | ** On output, signature->len == size of signature in buffer. |
496 | | ** Uses a random seed. |
497 | | */ |
498 | | SECStatus |
499 | | DSA_SignDigest(DSAPrivateKey *key, SECItem *signature, const SECItem *digest) |
500 | 0 | { |
501 | 0 | SECStatus rv; |
502 | 0 | int retries = 10; |
503 | 0 | unsigned char kSeed[DSA_MAX_SUBPRIME_LEN]; |
504 | 0 | unsigned int kSeedLen = 0; |
505 | 0 | unsigned int i; |
506 | 0 | unsigned int dsa_subprime_len = PQG_GetLength(&key->params.subPrime); |
507 | 0 | PRBool good; |
508 | |
|
509 | 0 | PORT_SetError(0); |
510 | 0 | do { |
511 | 0 | rv = dsa_GenerateGlobalRandomBytes(&key->params.subPrime, |
512 | 0 | kSeed, &kSeedLen, sizeof kSeed); |
513 | 0 | if (rv != SECSuccess) |
514 | 0 | break; |
515 | 0 | if (kSeedLen != dsa_subprime_len) { |
516 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
517 | 0 | rv = SECFailure; |
518 | 0 | break; |
519 | 0 | } |
520 | | /* Disallow a value of 0 for k. */ |
521 | 0 | good = PR_FALSE; |
522 | 0 | for (i = 0; i < kSeedLen; i++) { |
523 | 0 | if (kSeed[i] != 0) { |
524 | 0 | good = PR_TRUE; |
525 | 0 | break; |
526 | 0 | } |
527 | 0 | } |
528 | 0 | if (!good) { |
529 | 0 | PORT_SetError(SEC_ERROR_NEED_RANDOM); |
530 | 0 | rv = SECFailure; |
531 | 0 | continue; |
532 | 0 | } |
533 | 0 | rv = dsa_SignDigest(key, signature, digest, kSeed); |
534 | 0 | } while (rv != SECSuccess && PORT_GetError() == SEC_ERROR_NEED_RANDOM && |
535 | 0 | --retries > 0); |
536 | 0 | PORT_SafeZero(kSeed, sizeof kSeed); |
537 | 0 | return rv; |
538 | 0 | } |
539 | | |
540 | | /* For FIPS compliance testing. Seed must be exactly 20 bytes. */ |
541 | | SECStatus |
542 | | DSA_SignDigestWithSeed(DSAPrivateKey *key, |
543 | | SECItem *signature, |
544 | | const SECItem *digest, |
545 | | const unsigned char *seed) |
546 | 0 | { |
547 | 0 | SECStatus rv; |
548 | 0 | rv = dsa_SignDigest(key, signature, digest, seed); |
549 | 0 | return rv; |
550 | 0 | } |
551 | | |
552 | | /* signature is caller-supplied buffer of at least 20 bytes. |
553 | | ** On input, signature->len == size of buffer to hold signature. |
554 | | ** digest->len == size of digest. |
555 | | */ |
556 | | SECStatus |
557 | | DSA_VerifyDigest(DSAPublicKey *key, const SECItem *signature, |
558 | | const SECItem *digest) |
559 | 3.44k | { |
560 | | /* FIPS-compliance dictates that digest is a SHA hash. */ |
561 | 3.44k | mp_int p, q, g; /* PQG parameters */ |
562 | 3.44k | mp_int r_, s_; /* tuple (r', s') is received signature) */ |
563 | 3.44k | mp_int u1, u2, v, w; /* intermediate values used in verification */ |
564 | 3.44k | mp_int y; /* public key */ |
565 | 3.44k | mp_err err; |
566 | 3.44k | unsigned int dsa_subprime_len, dsa_signature_len, offset; |
567 | 3.44k | SECItem localDigest; |
568 | 3.44k | unsigned char localDigestData[DSA_MAX_SUBPRIME_LEN]; |
569 | 3.44k | SECStatus verified = SECFailure; |
570 | | |
571 | | /* Check args. */ |
572 | 3.44k | if (!key || !signature || !digest) { |
573 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
574 | 0 | return SECFailure; |
575 | 0 | } |
576 | | |
577 | 3.44k | dsa_subprime_len = PQG_GetLength(&key->params.subPrime); |
578 | 3.44k | dsa_signature_len = dsa_subprime_len * 2; |
579 | 3.44k | if ((dsa_subprime_len == 0) || |
580 | 3.44k | (dsa_subprime_len > DSA_MAX_SUBPRIME_LEN) || |
581 | 3.44k | (signature->len != dsa_signature_len) || |
582 | 3.44k | (digest->len > HASH_LENGTH_MAX) || |
583 | 3.44k | (digest->len < SHA1_LENGTH)) { |
584 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
585 | 0 | return SECFailure; |
586 | 0 | } |
587 | | |
588 | | /* DSA accepts digests not equal to dsa_subprime_len, if the |
589 | | * digests are greater, than they are truncated to the size of |
590 | | * dsa_subprime_len, using the left most bits. If they are less |
591 | | * then they are padded on the left.*/ |
592 | 3.44k | PORT_Memset(localDigestData, 0, dsa_subprime_len); |
593 | 3.44k | offset = (digest->len < dsa_subprime_len) ? (dsa_subprime_len - digest->len) : 0; |
594 | 3.44k | PORT_Memcpy(localDigestData + offset, digest->data, |
595 | 3.44k | dsa_subprime_len - offset); |
596 | 3.44k | localDigest.data = localDigestData; |
597 | 3.44k | localDigest.len = dsa_subprime_len; |
598 | | |
599 | | /* Initialize MPI integers. */ |
600 | 3.44k | MP_DIGITS(&p) = 0; |
601 | 3.44k | MP_DIGITS(&q) = 0; |
602 | 3.44k | MP_DIGITS(&g) = 0; |
603 | 3.44k | MP_DIGITS(&y) = 0; |
604 | 3.44k | MP_DIGITS(&r_) = 0; |
605 | 3.44k | MP_DIGITS(&s_) = 0; |
606 | 3.44k | MP_DIGITS(&u1) = 0; |
607 | 3.44k | MP_DIGITS(&u2) = 0; |
608 | 3.44k | MP_DIGITS(&v) = 0; |
609 | 3.44k | MP_DIGITS(&w) = 0; |
610 | 3.44k | CHECK_MPI_OK(mp_init(&p)); |
611 | 3.44k | CHECK_MPI_OK(mp_init(&q)); |
612 | 3.44k | CHECK_MPI_OK(mp_init(&g)); |
613 | 3.44k | CHECK_MPI_OK(mp_init(&y)); |
614 | 3.44k | CHECK_MPI_OK(mp_init(&r_)); |
615 | 3.44k | CHECK_MPI_OK(mp_init(&s_)); |
616 | 3.44k | CHECK_MPI_OK(mp_init(&u1)); |
617 | 3.44k | CHECK_MPI_OK(mp_init(&u2)); |
618 | 3.44k | CHECK_MPI_OK(mp_init(&v)); |
619 | 3.44k | CHECK_MPI_OK(mp_init(&w)); |
620 | | /* |
621 | | ** Convert stored PQG and public key into MPI integers. |
622 | | */ |
623 | 3.44k | SECITEM_TO_MPINT(key->params.prime, &p); |
624 | 3.44k | SECITEM_TO_MPINT(key->params.subPrime, &q); |
625 | 3.44k | SECITEM_TO_MPINT(key->params.base, &g); |
626 | 3.44k | SECITEM_TO_MPINT(key->publicValue, &y); |
627 | | /* |
628 | | ** Convert received signature (r', s') into MPI integers. |
629 | | */ |
630 | 3.44k | OCTETS_TO_MPINT(signature->data, &r_, dsa_subprime_len); |
631 | 3.44k | OCTETS_TO_MPINT(signature->data + dsa_subprime_len, &s_, dsa_subprime_len); |
632 | | /* |
633 | | ** Verify that 0 < r' < q and 0 < s' < q |
634 | | */ |
635 | 3.44k | if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || |
636 | 3.44k | mp_cmp(&r_, &q) >= 0 || mp_cmp(&s_, &q) >= 0) { |
637 | | /* err is zero here. */ |
638 | 15 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
639 | 15 | goto cleanup; /* will return verified == SECFailure */ |
640 | 15 | } |
641 | | /* |
642 | | ** FIPS 186-1, Section 6, Step 1 |
643 | | ** |
644 | | ** w = (s')**-1 mod q |
645 | | */ |
646 | 3.43k | CHECK_MPI_OK(mp_invmod(&s_, &q, &w)); /* w = (s')**-1 mod q */ |
647 | | /* |
648 | | ** FIPS 186-1, Section 6, Step 2 |
649 | | ** |
650 | | ** u1 = ((Hash(M')) * w) mod q |
651 | | */ |
652 | 3.14k | SECITEM_TO_MPINT(localDigest, &u1); /* u1 = HASH(M') */ |
653 | 3.14k | CHECK_MPI_OK(mp_mulmod(&u1, &w, &q, &u1)); /* u1 = u1 * w mod q */ |
654 | | /* |
655 | | ** FIPS 186-1, Section 6, Step 3 |
656 | | ** |
657 | | ** u2 = ((r') * w) mod q |
658 | | */ |
659 | 3.14k | CHECK_MPI_OK(mp_mulmod(&r_, &w, &q, &u2)); |
660 | | /* |
661 | | ** FIPS 186-1, Section 6, Step 4 |
662 | | ** |
663 | | ** v = ((g**u1 * y**u2) mod p) mod q |
664 | | */ |
665 | 3.14k | CHECK_MPI_OK(mp_exptmod(&g, &u1, &p, &g)); /* g = g**u1 mod p */ |
666 | 3.14k | CHECK_MPI_OK(mp_exptmod(&y, &u2, &p, &y)); /* y = y**u2 mod p */ |
667 | 3.14k | CHECK_MPI_OK(mp_mulmod(&g, &y, &p, &v)); /* v = g * y mod p */ |
668 | 3.14k | CHECK_MPI_OK(mp_mod(&v, &q, &v)); /* v = v mod q */ |
669 | | /* |
670 | | ** Verification: v == r' |
671 | | */ |
672 | 3.14k | if (mp_cmp(&v, &r_)) { |
673 | 2.89k | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
674 | 2.89k | verified = SECFailure; /* Signature failed to verify. */ |
675 | 2.89k | } else { |
676 | 246 | verified = SECSuccess; /* Signature verified. */ |
677 | 246 | } |
678 | 3.44k | cleanup: |
679 | 3.44k | PORT_SafeZero(localDigestData, sizeof localDigestData); |
680 | 3.44k | mp_clear(&p); |
681 | 3.44k | mp_clear(&q); |
682 | 3.44k | mp_clear(&g); |
683 | 3.44k | mp_clear(&y); |
684 | 3.44k | mp_clear(&r_); |
685 | 3.44k | mp_clear(&s_); |
686 | 3.44k | mp_clear(&u1); |
687 | 3.44k | mp_clear(&u2); |
688 | 3.44k | mp_clear(&v); |
689 | 3.44k | mp_clear(&w); |
690 | 3.44k | if (err) { |
691 | 293 | translate_mpi_error(err); |
692 | 293 | } |
693 | 3.44k | return verified; |
694 | 3.14k | } |