Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/freebl/dh.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 } |