|
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 /* |
|
6 * Diffie-Hellman parameter generation, key generation, and secret derivation. |
|
7 * KEA secret generation and verification. |
|
8 */ |
|
9 #ifdef FREEBL_NO_DEPEND |
|
10 #include "stubs.h" |
|
11 #endif |
|
12 |
|
13 #include "prerr.h" |
|
14 #include "secerr.h" |
|
15 |
|
16 #include "blapi.h" |
|
17 #include "secitem.h" |
|
18 #include "mpi.h" |
|
19 #include "mpprime.h" |
|
20 #include "secmpi.h" |
|
21 |
|
22 #define KEA_DERIVED_SECRET_LEN 128 |
|
23 |
|
24 /* Lengths are in bytes. */ |
|
25 static unsigned int |
|
26 dh_GetSecretKeyLen(unsigned int primeLen) |
|
27 { |
|
28 /* Based on Table 2 in NIST SP 800-57. */ |
|
29 if (primeLen >= 1920) { /* 15360 bits */ |
|
30 return 64; /* 512 bits */ |
|
31 } |
|
32 if (primeLen >= 960) { /* 7680 bits */ |
|
33 return 48; /* 384 bits */ |
|
34 } |
|
35 if (primeLen >= 384) { /* 3072 bits */ |
|
36 return 32; /* 256 bits */ |
|
37 } |
|
38 if (primeLen >= 256) { /* 2048 bits */ |
|
39 return 28; /* 224 bits */ |
|
40 } |
|
41 return 20; /* 160 bits */ |
|
42 } |
|
43 |
|
44 SECStatus |
|
45 DH_GenParam(int primeLen, DHParams **params) |
|
46 { |
|
47 PLArenaPool *arena; |
|
48 DHParams *dhparams; |
|
49 unsigned char *pb = NULL; |
|
50 unsigned char *ab = NULL; |
|
51 unsigned long counter = 0; |
|
52 mp_int p, q, a, h, psub1, test; |
|
53 mp_err err = MP_OKAY; |
|
54 SECStatus rv = SECSuccess; |
|
55 if (!params || primeLen < 0) { |
|
56 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
57 return SECFailure; |
|
58 } |
|
59 arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); |
|
60 if (!arena) { |
|
61 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
62 return SECFailure; |
|
63 } |
|
64 dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams)); |
|
65 if (!dhparams) { |
|
66 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
67 PORT_FreeArena(arena, PR_TRUE); |
|
68 return SECFailure; |
|
69 } |
|
70 dhparams->arena = arena; |
|
71 MP_DIGITS(&p) = 0; |
|
72 MP_DIGITS(&q) = 0; |
|
73 MP_DIGITS(&a) = 0; |
|
74 MP_DIGITS(&h) = 0; |
|
75 MP_DIGITS(&psub1) = 0; |
|
76 MP_DIGITS(&test) = 0; |
|
77 CHECK_MPI_OK( mp_init(&p) ); |
|
78 CHECK_MPI_OK( mp_init(&q) ); |
|
79 CHECK_MPI_OK( mp_init(&a) ); |
|
80 CHECK_MPI_OK( mp_init(&h) ); |
|
81 CHECK_MPI_OK( mp_init(&psub1) ); |
|
82 CHECK_MPI_OK( mp_init(&test) ); |
|
83 /* generate prime with MPI, uses Miller-Rabin to generate strong prime. */ |
|
84 pb = PORT_Alloc(primeLen); |
|
85 CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(pb, primeLen) ); |
|
86 pb[0] |= 0x80; /* set high-order bit */ |
|
87 pb[primeLen-1] |= 0x01; /* set low-order bit */ |
|
88 CHECK_MPI_OK( mp_read_unsigned_octets(&p, pb, primeLen) ); |
|
89 CHECK_MPI_OK( mpp_make_prime(&p, primeLen * 8, PR_TRUE, &counter) ); |
|
90 /* construct Sophie-Germain prime q = (p-1)/2. */ |
|
91 CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); |
|
92 CHECK_MPI_OK( mp_div_2(&psub1, &q) ); |
|
93 /* construct a generator from the prime. */ |
|
94 ab = PORT_Alloc(primeLen); |
|
95 /* generate a candidate number a in p's field */ |
|
96 CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(ab, primeLen) ); |
|
97 CHECK_MPI_OK( mp_read_unsigned_octets(&a, ab, primeLen) ); |
|
98 /* force a < p (note that quot(a/p) <= 1) */ |
|
99 if ( mp_cmp(&a, &p) > 0 ) |
|
100 CHECK_MPI_OK( mp_sub(&a, &p, &a) ); |
|
101 do { |
|
102 /* check that a is in the range [2..p-1] */ |
|
103 if ( mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) { |
|
104 /* a is outside of the allowed range. Set a=3 and keep going. */ |
|
105 mp_set(&a, 3); |
|
106 } |
|
107 /* if a**q mod p != 1 then a is a generator */ |
|
108 CHECK_MPI_OK( mp_exptmod(&a, &q, &p, &test) ); |
|
109 if ( mp_cmp_d(&test, 1) != 0 ) |
|
110 break; |
|
111 /* increment the candidate and try again. */ |
|
112 CHECK_MPI_OK( mp_add_d(&a, 1, &a) ); |
|
113 } while (PR_TRUE); |
|
114 MPINT_TO_SECITEM(&p, &dhparams->prime, arena); |
|
115 MPINT_TO_SECITEM(&a, &dhparams->base, arena); |
|
116 *params = dhparams; |
|
117 cleanup: |
|
118 mp_clear(&p); |
|
119 mp_clear(&q); |
|
120 mp_clear(&a); |
|
121 mp_clear(&h); |
|
122 mp_clear(&psub1); |
|
123 mp_clear(&test); |
|
124 if (pb) PORT_ZFree(pb, primeLen); |
|
125 if (ab) PORT_ZFree(ab, primeLen); |
|
126 if (err) { |
|
127 MP_TO_SEC_ERROR(err); |
|
128 rv = SECFailure; |
|
129 } |
|
130 if (rv) |
|
131 PORT_FreeArena(arena, PR_TRUE); |
|
132 return rv; |
|
133 } |
|
134 |
|
135 SECStatus |
|
136 DH_NewKey(DHParams *params, DHPrivateKey **privKey) |
|
137 { |
|
138 PLArenaPool *arena; |
|
139 DHPrivateKey *key; |
|
140 mp_int g, xa, p, Ya; |
|
141 mp_err err = MP_OKAY; |
|
142 SECStatus rv = SECSuccess; |
|
143 if (!params || !privKey) { |
|
144 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
145 return SECFailure; |
|
146 } |
|
147 arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE); |
|
148 if (!arena) { |
|
149 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
150 return SECFailure; |
|
151 } |
|
152 key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey)); |
|
153 if (!key) { |
|
154 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
155 PORT_FreeArena(arena, PR_TRUE); |
|
156 return SECFailure; |
|
157 } |
|
158 key->arena = arena; |
|
159 MP_DIGITS(&g) = 0; |
|
160 MP_DIGITS(&xa) = 0; |
|
161 MP_DIGITS(&p) = 0; |
|
162 MP_DIGITS(&Ya) = 0; |
|
163 CHECK_MPI_OK( mp_init(&g) ); |
|
164 CHECK_MPI_OK( mp_init(&xa) ); |
|
165 CHECK_MPI_OK( mp_init(&p) ); |
|
166 CHECK_MPI_OK( mp_init(&Ya) ); |
|
167 /* Set private key's p */ |
|
168 CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, ¶ms->prime) ); |
|
169 SECITEM_TO_MPINT(key->prime, &p); |
|
170 /* Set private key's g */ |
|
171 CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->base) ); |
|
172 SECITEM_TO_MPINT(key->base, &g); |
|
173 /* Generate private key xa */ |
|
174 SECITEM_AllocItem(arena, &key->privateValue, |
|
175 dh_GetSecretKeyLen(params->prime.len)); |
|
176 RNG_GenerateGlobalRandomBytes(key->privateValue.data, |
|
177 key->privateValue.len); |
|
178 SECITEM_TO_MPINT( key->privateValue, &xa ); |
|
179 /* xa < p */ |
|
180 CHECK_MPI_OK( mp_mod(&xa, &p, &xa) ); |
|
181 /* Compute public key Ya = g ** xa mod p */ |
|
182 CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) ); |
|
183 MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena); |
|
184 *privKey = key; |
|
185 cleanup: |
|
186 mp_clear(&g); |
|
187 mp_clear(&xa); |
|
188 mp_clear(&p); |
|
189 mp_clear(&Ya); |
|
190 if (err) { |
|
191 MP_TO_SEC_ERROR(err); |
|
192 rv = SECFailure; |
|
193 } |
|
194 if (rv) |
|
195 PORT_FreeArena(arena, PR_TRUE); |
|
196 return rv; |
|
197 } |
|
198 |
|
199 SECStatus |
|
200 DH_Derive(SECItem *publicValue, |
|
201 SECItem *prime, |
|
202 SECItem *privateValue, |
|
203 SECItem *derivedSecret, |
|
204 unsigned int outBytes) |
|
205 { |
|
206 mp_int p, Xa, Yb, ZZ, psub1; |
|
207 mp_err err = MP_OKAY; |
|
208 int len = 0; |
|
209 unsigned int nb; |
|
210 unsigned char *secret = NULL; |
|
211 if (!publicValue || !prime || !privateValue || !derivedSecret) { |
|
212 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
213 return SECFailure; |
|
214 } |
|
215 memset(derivedSecret, 0, sizeof *derivedSecret); |
|
216 MP_DIGITS(&p) = 0; |
|
217 MP_DIGITS(&Xa) = 0; |
|
218 MP_DIGITS(&Yb) = 0; |
|
219 MP_DIGITS(&ZZ) = 0; |
|
220 MP_DIGITS(&psub1) = 0; |
|
221 CHECK_MPI_OK( mp_init(&p) ); |
|
222 CHECK_MPI_OK( mp_init(&Xa) ); |
|
223 CHECK_MPI_OK( mp_init(&Yb) ); |
|
224 CHECK_MPI_OK( mp_init(&ZZ) ); |
|
225 CHECK_MPI_OK( mp_init(&psub1) ); |
|
226 SECITEM_TO_MPINT(*publicValue, &Yb); |
|
227 SECITEM_TO_MPINT(*privateValue, &Xa); |
|
228 SECITEM_TO_MPINT(*prime, &p); |
|
229 CHECK_MPI_OK( mp_sub_d(&p, 1, &psub1) ); |
|
230 |
|
231 /* We assume that the modulus, p, is a safe prime. That is, p = 2q+1 where |
|
232 * q is also a prime. Thus the orders of the subgroups are factors of 2q: |
|
233 * namely 1, 2, q and 2q. |
|
234 * |
|
235 * We check that the peer's public value isn't zero (which isn't in the |
|
236 * group), one (subgroup of order one) or p-1 (subgroup of order 2). We |
|
237 * also check that the public value is less than p, to avoid being fooled |
|
238 * by values like p+1 or 2*p-1. |
|
239 * |
|
240 * Thus we must be operating in the subgroup of size q or 2q. */ |
|
241 if (mp_cmp_d(&Yb, 1) <= 0 || |
|
242 mp_cmp(&Yb, &psub1) >= 0) { |
|
243 err = MP_BADARG; |
|
244 goto cleanup; |
|
245 } |
|
246 |
|
247 /* ZZ = (Yb)**Xa mod p */ |
|
248 CHECK_MPI_OK( mp_exptmod(&Yb, &Xa, &p, &ZZ) ); |
|
249 /* number of bytes in the derived secret */ |
|
250 len = mp_unsigned_octet_size(&ZZ); |
|
251 if (len <= 0) { |
|
252 err = MP_BADARG; |
|
253 goto cleanup; |
|
254 } |
|
255 /* allocate a buffer which can hold the entire derived secret. */ |
|
256 secret = PORT_Alloc(len); |
|
257 /* grab the derived secret */ |
|
258 err = mp_to_unsigned_octets(&ZZ, secret, len); |
|
259 if (err >= 0) err = MP_OKAY; |
|
260 /* |
|
261 ** if outBytes is 0 take all of the bytes from the derived secret. |
|
262 ** if outBytes is not 0 take exactly outBytes from the derived secret, zero |
|
263 ** pad at the beginning if necessary, and truncate beginning bytes |
|
264 ** if necessary. |
|
265 */ |
|
266 if (outBytes > 0) |
|
267 nb = outBytes; |
|
268 else |
|
269 nb = len; |
|
270 SECITEM_AllocItem(NULL, derivedSecret, nb); |
|
271 if (len < nb) { |
|
272 unsigned int offset = nb - len; |
|
273 memset(derivedSecret->data, 0, offset); |
|
274 memcpy(derivedSecret->data + offset, secret, len); |
|
275 } else { |
|
276 memcpy(derivedSecret->data, secret + len - nb, nb); |
|
277 } |
|
278 cleanup: |
|
279 mp_clear(&p); |
|
280 mp_clear(&Xa); |
|
281 mp_clear(&Yb); |
|
282 mp_clear(&ZZ); |
|
283 mp_clear(&psub1); |
|
284 if (secret) { |
|
285 /* free the buffer allocated for the full secret. */ |
|
286 PORT_ZFree(secret, len); |
|
287 } |
|
288 if (err) { |
|
289 MP_TO_SEC_ERROR(err); |
|
290 if (derivedSecret->data) |
|
291 PORT_ZFree(derivedSecret->data, derivedSecret->len); |
|
292 return SECFailure; |
|
293 } |
|
294 return SECSuccess; |
|
295 } |
|
296 |
|
297 SECStatus |
|
298 KEA_Derive(SECItem *prime, |
|
299 SECItem *public1, |
|
300 SECItem *public2, |
|
301 SECItem *private1, |
|
302 SECItem *private2, |
|
303 SECItem *derivedSecret) |
|
304 { |
|
305 mp_int p, Y, R, r, x, t, u, w; |
|
306 mp_err err; |
|
307 unsigned char *secret = NULL; |
|
308 unsigned int len = 0, offset; |
|
309 if (!prime || !public1 || !public2 || !private1 || !private2 || |
|
310 !derivedSecret) { |
|
311 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
312 return SECFailure; |
|
313 } |
|
314 memset(derivedSecret, 0, sizeof *derivedSecret); |
|
315 MP_DIGITS(&p) = 0; |
|
316 MP_DIGITS(&Y) = 0; |
|
317 MP_DIGITS(&R) = 0; |
|
318 MP_DIGITS(&r) = 0; |
|
319 MP_DIGITS(&x) = 0; |
|
320 MP_DIGITS(&t) = 0; |
|
321 MP_DIGITS(&u) = 0; |
|
322 MP_DIGITS(&w) = 0; |
|
323 CHECK_MPI_OK( mp_init(&p) ); |
|
324 CHECK_MPI_OK( mp_init(&Y) ); |
|
325 CHECK_MPI_OK( mp_init(&R) ); |
|
326 CHECK_MPI_OK( mp_init(&r) ); |
|
327 CHECK_MPI_OK( mp_init(&x) ); |
|
328 CHECK_MPI_OK( mp_init(&t) ); |
|
329 CHECK_MPI_OK( mp_init(&u) ); |
|
330 CHECK_MPI_OK( mp_init(&w) ); |
|
331 SECITEM_TO_MPINT(*prime, &p); |
|
332 SECITEM_TO_MPINT(*public1, &Y); |
|
333 SECITEM_TO_MPINT(*public2, &R); |
|
334 SECITEM_TO_MPINT(*private1, &r); |
|
335 SECITEM_TO_MPINT(*private2, &x); |
|
336 /* t = DH(Y, r, p) = Y ** r mod p */ |
|
337 CHECK_MPI_OK( mp_exptmod(&Y, &r, &p, &t) ); |
|
338 /* u = DH(R, x, p) = R ** x mod p */ |
|
339 CHECK_MPI_OK( mp_exptmod(&R, &x, &p, &u) ); |
|
340 /* w = (t + u) mod p */ |
|
341 CHECK_MPI_OK( mp_addmod(&t, &u, &p, &w) ); |
|
342 /* allocate a buffer for the full derived secret */ |
|
343 len = mp_unsigned_octet_size(&w); |
|
344 secret = PORT_Alloc(len); |
|
345 /* grab the secret */ |
|
346 err = mp_to_unsigned_octets(&w, secret, len); |
|
347 if (err > 0) err = MP_OKAY; |
|
348 /* allocate output buffer */ |
|
349 SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN); |
|
350 memset(derivedSecret->data, 0, derivedSecret->len); |
|
351 /* copy in the 128 lsb of the secret */ |
|
352 if (len >= KEA_DERIVED_SECRET_LEN) { |
|
353 memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN), |
|
354 KEA_DERIVED_SECRET_LEN); |
|
355 } else { |
|
356 offset = KEA_DERIVED_SECRET_LEN - len; |
|
357 memcpy(derivedSecret->data + offset, secret, len); |
|
358 } |
|
359 cleanup: |
|
360 mp_clear(&p); |
|
361 mp_clear(&Y); |
|
362 mp_clear(&R); |
|
363 mp_clear(&r); |
|
364 mp_clear(&x); |
|
365 mp_clear(&t); |
|
366 mp_clear(&u); |
|
367 mp_clear(&w); |
|
368 if (secret) |
|
369 PORT_ZFree(secret, len); |
|
370 if (err) { |
|
371 MP_TO_SEC_ERROR(err); |
|
372 return SECFailure; |
|
373 } |
|
374 return SECSuccess; |
|
375 } |
|
376 |
|
377 PRBool |
|
378 KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime) |
|
379 { |
|
380 mp_int p, q, y, r; |
|
381 mp_err err; |
|
382 int cmp = 1; /* default is false */ |
|
383 if (!Y || !prime || !subPrime) { |
|
384 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
385 return SECFailure; |
|
386 } |
|
387 MP_DIGITS(&p) = 0; |
|
388 MP_DIGITS(&q) = 0; |
|
389 MP_DIGITS(&y) = 0; |
|
390 MP_DIGITS(&r) = 0; |
|
391 CHECK_MPI_OK( mp_init(&p) ); |
|
392 CHECK_MPI_OK( mp_init(&q) ); |
|
393 CHECK_MPI_OK( mp_init(&y) ); |
|
394 CHECK_MPI_OK( mp_init(&r) ); |
|
395 SECITEM_TO_MPINT(*prime, &p); |
|
396 SECITEM_TO_MPINT(*subPrime, &q); |
|
397 SECITEM_TO_MPINT(*Y, &y); |
|
398 /* compute r = y**q mod p */ |
|
399 CHECK_MPI_OK( mp_exptmod(&y, &q, &p, &r) ); |
|
400 /* compare to 1 */ |
|
401 cmp = mp_cmp_d(&r, 1); |
|
402 cleanup: |
|
403 mp_clear(&p); |
|
404 mp_clear(&q); |
|
405 mp_clear(&y); |
|
406 mp_clear(&r); |
|
407 if (err) { |
|
408 MP_TO_SEC_ERROR(err); |
|
409 return PR_FALSE; |
|
410 } |
|
411 return (cmp == 0) ? PR_TRUE : PR_FALSE; |
|
412 } |