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  |  | /*  | 
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 "blapii.h"  | 
18  |  | #include "secitem.h"  | 
19  |  | #include "mpi.h"  | 
20  |  | #include "secmpi.h"  | 
21  |  |  | 
22  | 0  | #define KEA_DERIVED_SECRET_LEN 128  | 
23  |  |  | 
24  |  | /* Lengths are in bytes. */  | 
25  |  | static unsigned int  | 
26  |  | dh_GetSecretKeyLen(unsigned int primeLen)  | 
27  | 0  | { | 
28  |  |     /* Based on Table 2 in NIST SP 800-57. */  | 
29  | 0  |     if (primeLen >= 1920) { /* 15360 bits */ | 
30  | 0  |         return 64;          /* 512 bits */  | 
31  | 0  |     }  | 
32  | 0  |     if (primeLen >= 960) { /* 7680 bits */ | 
33  | 0  |         return 48;         /* 384 bits */  | 
34  | 0  |     }  | 
35  | 0  |     if (primeLen >= 384) { /* 3072 bits */ | 
36  | 0  |         return 32;         /* 256 bits */  | 
37  | 0  |     }  | 
38  | 0  |     if (primeLen >= 256) { /* 2048 bits */ | 
39  | 0  |         return 28;         /* 224 bits */  | 
40  | 0  |     }  | 
41  | 0  |     return 20; /* 160 bits */  | 
42  | 0  | }  | 
43  |  |  | 
44  |  | SECStatus  | 
45  |  | DH_GenParam(int primeLen, DHParams **params)  | 
46  | 0  | { | 
47  | 0  |     PLArenaPool *arena;  | 
48  | 0  |     DHParams *dhparams;  | 
49  | 0  |     unsigned char *ab = NULL;  | 
50  | 0  |     mp_int p, q, a, h, psub1, test;  | 
51  | 0  |     mp_err err = MP_OKAY;  | 
52  | 0  |     SECStatus rv = SECSuccess;  | 
53  | 0  |     if (!params || primeLen < 0) { | 
54  | 0  |         PORT_SetError(SEC_ERROR_INVALID_ARGS);  | 
55  | 0  |         return SECFailure;  | 
56  | 0  |     }  | 
57  | 0  |     arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);  | 
58  | 0  |     if (!arena) { | 
59  | 0  |         PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
60  | 0  |         return SECFailure;  | 
61  | 0  |     }  | 
62  | 0  |     dhparams = (DHParams *)PORT_ArenaZAlloc(arena, sizeof(DHParams));  | 
63  | 0  |     if (!dhparams) { | 
64  | 0  |         PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
65  | 0  |         PORT_FreeArena(arena, PR_TRUE);  | 
66  | 0  |         return SECFailure;  | 
67  | 0  |     }  | 
68  | 0  |     dhparams->arena = arena;  | 
69  | 0  |     MP_DIGITS(&p) = 0;  | 
70  | 0  |     MP_DIGITS(&q) = 0;  | 
71  | 0  |     MP_DIGITS(&a) = 0;  | 
72  | 0  |     MP_DIGITS(&h) = 0;  | 
73  | 0  |     MP_DIGITS(&psub1) = 0;  | 
74  | 0  |     MP_DIGITS(&test) = 0;  | 
75  | 0  |     CHECK_MPI_OK(mp_init(&p));  | 
76  | 0  |     CHECK_MPI_OK(mp_init(&q));  | 
77  | 0  |     CHECK_MPI_OK(mp_init(&a));  | 
78  | 0  |     CHECK_MPI_OK(mp_init(&h));  | 
79  | 0  |     CHECK_MPI_OK(mp_init(&psub1));  | 
80  | 0  |     CHECK_MPI_OK(mp_init(&test));  | 
81  |  |     /* generate prime with MPI, uses Miller-Rabin to generate safe prime. */  | 
82  | 0  |     CHECK_SEC_OK(generate_prime(&p, primeLen));  | 
83  |  |     /* construct Sophie-Germain prime q = (p-1)/2. */  | 
84  | 0  |     CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));  | 
85  | 0  |     CHECK_MPI_OK(mp_div_2(&psub1, &q));  | 
86  |  |     /* construct a generator from the prime. */  | 
87  | 0  |     ab = PORT_Alloc(primeLen);  | 
88  | 0  |     if (!ab) { | 
89  | 0  |         PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
90  | 0  |         rv = SECFailure;  | 
91  | 0  |         goto cleanup;  | 
92  | 0  |     }  | 
93  |  |     /* generate a candidate number a in p's field */  | 
94  | 0  |     CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(ab, primeLen));  | 
95  | 0  |     CHECK_MPI_OK(mp_read_unsigned_octets(&a, ab, primeLen));  | 
96  |  |     /* force a < p (note that quot(a/p) <= 1) */  | 
97  | 0  |     if (mp_cmp(&a, &p) > 0)  | 
98  | 0  |         CHECK_MPI_OK(mp_sub(&a, &p, &a));  | 
99  | 0  |     do { | 
100  |  |         /* check that a is in the range [2..p-1] */  | 
101  | 0  |         if (mp_cmp_d(&a, 2) < 0 || mp_cmp(&a, &psub1) >= 0) { | 
102  |  |             /* a is outside of the allowed range.  Set a=3 and keep going. */  | 
103  | 0  |             mp_set(&a, 3);  | 
104  | 0  |         }  | 
105  |  |         /* if a**q mod p != 1 then a is a generator */  | 
106  | 0  |         CHECK_MPI_OK(mp_exptmod(&a, &q, &p, &test));  | 
107  | 0  |         if (mp_cmp_d(&test, 1) != 0)  | 
108  | 0  |             break;  | 
109  |  |         /* increment the candidate and try again. */  | 
110  | 0  |         CHECK_MPI_OK(mp_add_d(&a, 1, &a));  | 
111  | 0  |     } while (PR_TRUE);  | 
112  | 0  |     MPINT_TO_SECITEM(&p, &dhparams->prime, arena);  | 
113  | 0  |     MPINT_TO_SECITEM(&a, &dhparams->base, arena);  | 
114  | 0  |     *params = dhparams;  | 
115  | 0  | cleanup:  | 
116  | 0  |     mp_clear(&p);  | 
117  | 0  |     mp_clear(&q);  | 
118  | 0  |     mp_clear(&a);  | 
119  | 0  |     mp_clear(&h);  | 
120  | 0  |     mp_clear(&psub1);  | 
121  | 0  |     mp_clear(&test);  | 
122  | 0  |     if (ab) { | 
123  | 0  |         PORT_ZFree(ab, primeLen);  | 
124  | 0  |     }  | 
125  | 0  |     if (err) { | 
126  | 0  |         MP_TO_SEC_ERROR(err);  | 
127  | 0  |         rv = SECFailure;  | 
128  | 0  |     }  | 
129  | 0  |     if (rv != SECSuccess) { | 
130  | 0  |         PORT_FreeArena(arena, PR_TRUE);  | 
131  | 0  |     }  | 
132  | 0  |     return rv;  | 
133  | 0  | }  | 
134  |  |  | 
135  |  | SECStatus  | 
136  |  | DH_NewKey(DHParams *params, DHPrivateKey **privKey)  | 
137  | 0  | { | 
138  | 0  |     PLArenaPool *arena;  | 
139  | 0  |     DHPrivateKey *key;  | 
140  | 0  |     mp_int g, xa, p, Ya;  | 
141  | 0  |     mp_err err = MP_OKAY;  | 
142  | 0  |     SECStatus rv = SECSuccess;  | 
143  | 0  |     if (!params || !privKey) { | 
144  | 0  |         PORT_SetError(SEC_ERROR_INVALID_ARGS);  | 
145  | 0  |         return SECFailure;  | 
146  | 0  |     }  | 
147  | 0  |     arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);  | 
148  | 0  |     if (!arena) { | 
149  | 0  |         PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
150  | 0  |         return SECFailure;  | 
151  | 0  |     }  | 
152  | 0  |     key = (DHPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DHPrivateKey));  | 
153  | 0  |     if (!key) { | 
154  | 0  |         PORT_SetError(SEC_ERROR_NO_MEMORY);  | 
155  | 0  |         PORT_FreeArena(arena, PR_TRUE);  | 
156  | 0  |         return SECFailure;  | 
157  | 0  |     }  | 
158  | 0  |     key->arena = arena;  | 
159  | 0  |     MP_DIGITS(&g) = 0;  | 
160  | 0  |     MP_DIGITS(&xa) = 0;  | 
161  | 0  |     MP_DIGITS(&p) = 0;  | 
162  | 0  |     MP_DIGITS(&Ya) = 0;  | 
163  | 0  |     CHECK_MPI_OK(mp_init(&g));  | 
164  | 0  |     CHECK_MPI_OK(mp_init(&xa));  | 
165  | 0  |     CHECK_MPI_OK(mp_init(&p));  | 
166  | 0  |     CHECK_MPI_OK(mp_init(&Ya));  | 
167  |  |     /* Set private key's p */  | 
168  | 0  |     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->prime, ¶ms->prime));  | 
169  | 0  |     SECITEM_TO_MPINT(key->prime, &p);  | 
170  |  |     /* Set private key's g */  | 
171  | 0  |     CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->base, ¶ms->base));  | 
172  | 0  |     SECITEM_TO_MPINT(key->base, &g);  | 
173  |  |     /* Generate private key xa */  | 
174  | 0  |     SECITEM_AllocItem(arena, &key->privateValue,  | 
175  | 0  |                       dh_GetSecretKeyLen(params->prime.len));  | 
176  | 0  |     CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(key->privateValue.data,  | 
177  | 0  |                                                key->privateValue.len));  | 
178  | 0  |     SECITEM_TO_MPINT(key->privateValue, &xa);  | 
179  |  |     /* xa < p */  | 
180  | 0  |     CHECK_MPI_OK(mp_mod(&xa, &p, &xa));  | 
181  |  | /* Compute public key Ya = g ** xa mod p */  | 
182  | 0  | #ifndef UNSAFE_FUZZER_MODE  | 
183  | 0  |     CHECK_MPI_OK(mp_exptmod(&g, &xa, &p, &Ya));  | 
184  | 0  | #endif  | 
185  | 0  |     MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);  | 
186  | 0  |     *privKey = key;  | 
187  | 0  | cleanup:  | 
188  | 0  |     mp_clear(&g);  | 
189  | 0  |     mp_clear(&xa);  | 
190  | 0  |     mp_clear(&p);  | 
191  | 0  |     mp_clear(&Ya);  | 
192  | 0  |     if (err) { | 
193  | 0  |         MP_TO_SEC_ERROR(err);  | 
194  | 0  |         rv = SECFailure;  | 
195  | 0  |     }  | 
196  | 0  |     if (rv) { | 
197  | 0  |         *privKey = NULL;  | 
198  | 0  |         PORT_FreeArena(arena, PR_TRUE);  | 
199  | 0  |     }  | 
200  | 0  |     return rv;  | 
201  | 0  | }  | 
202  |  |  | 
203  |  | SECStatus  | 
204  |  | DH_Derive(SECItem *publicValue,  | 
205  |  |           SECItem *prime,  | 
206  |  |           SECItem *privateValue,  | 
207  |  |           SECItem *derivedSecret,  | 
208  |  |           unsigned int outBytes)  | 
209  | 0  | { | 
210  | 0  |     mp_int p, Xa, Yb, ZZ, psub1;  | 
211  | 0  |     mp_err err = MP_OKAY;  | 
212  | 0  |     unsigned int len = 0;  | 
213  | 0  |     unsigned int nb;  | 
214  | 0  |     unsigned char *secret = NULL;  | 
215  | 0  |     if (!publicValue || !publicValue->len || !prime || !prime->len ||  | 
216  | 0  |         !privateValue || !privateValue->len || !derivedSecret) { | 
217  | 0  |         PORT_SetError(SEC_ERROR_INVALID_ARGS);  | 
218  | 0  |         return SECFailure;  | 
219  | 0  |     }  | 
220  | 0  |     memset(derivedSecret, 0, sizeof *derivedSecret);  | 
221  | 0  |     MP_DIGITS(&p) = 0;  | 
222  | 0  |     MP_DIGITS(&Xa) = 0;  | 
223  | 0  |     MP_DIGITS(&Yb) = 0;  | 
224  | 0  |     MP_DIGITS(&ZZ) = 0;  | 
225  | 0  |     MP_DIGITS(&psub1) = 0;  | 
226  | 0  |     CHECK_MPI_OK(mp_init(&p));  | 
227  | 0  |     CHECK_MPI_OK(mp_init(&Xa));  | 
228  | 0  |     CHECK_MPI_OK(mp_init(&Yb));  | 
229  | 0  |     CHECK_MPI_OK(mp_init(&ZZ));  | 
230  | 0  |     CHECK_MPI_OK(mp_init(&psub1));  | 
231  | 0  |     SECITEM_TO_MPINT(*publicValue, &Yb);  | 
232  | 0  |     SECITEM_TO_MPINT(*privateValue, &Xa);  | 
233  | 0  |     SECITEM_TO_MPINT(*prime, &p);  | 
234  | 0  |     CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));  | 
235  |  |  | 
236  |  |     /* We assume that the modulus, p, is a safe prime. That is, p = 2q+1 where  | 
237  |  |      * q is also a prime. Thus the orders of the subgroups are factors of 2q:  | 
238  |  |      * namely 1, 2, q and 2q.  | 
239  |  |      *  | 
240  |  |      * We check that the peer's public value isn't zero (which isn't in the  | 
241  |  |      * group), one (subgroup of order one) or p-1 (subgroup of order 2). We  | 
242  |  |      * also check that the public value is less than p, to avoid being fooled  | 
243  |  |      * by values like p+1 or 2*p-1.  | 
244  |  |      *  | 
245  |  |      * Thus we must be operating in the subgroup of size q or 2q. */  | 
246  | 0  |     if (mp_cmp_d(&Yb, 1) <= 0 ||  | 
247  | 0  |         mp_cmp(&Yb, &psub1) >= 0) { | 
248  | 0  |         err = MP_BADARG;  | 
249  | 0  |         goto cleanup;  | 
250  | 0  |     }  | 
251  |  |  | 
252  |  |     /* ZZ = (Yb)**Xa mod p */  | 
253  | 0  |     CHECK_MPI_OK(mp_exptmod(&Yb, &Xa, &p, &ZZ));  | 
254  |  |     /* number of bytes in the derived secret */  | 
255  | 0  |     len = mp_unsigned_octet_size(&ZZ);  | 
256  | 0  |     if (len <= 0) { | 
257  | 0  |         err = MP_BADARG;  | 
258  | 0  |         goto cleanup;  | 
259  | 0  |     }  | 
260  |  |  | 
261  |  |     /*  | 
262  |  |      * We check to make sure that ZZ is not equal to 0, 1 or -1 mod p.  | 
263  |  |      * This helps guard against small subgroup attacks, since an attacker  | 
264  |  |      * using a subgroup of size N will produce 0, 1 or -1 with probability 1/N.  | 
265  |  |      * When the protocol is executed within a properly large subgroup, the  | 
266  |  |      * probability of this result will be negligibly small.  For example,  | 
267  |  |      * with a safe prime of the form 2q+1, the probability will be 1/q.  | 
268  |  |      *  | 
269  |  |      * We return MP_BADARG because this is probably the result of a bad  | 
270  |  |      * public value or a bad prime having been provided.  | 
271  |  |      */  | 
272  | 0  |     if (mp_cmp_d(&ZZ, 0) == 0 || mp_cmp_d(&ZZ, 1) == 0 ||  | 
273  | 0  |         mp_cmp(&ZZ, &psub1) == 0) { | 
274  | 0  |         err = MP_BADARG;  | 
275  | 0  |         goto cleanup;  | 
276  | 0  |     }  | 
277  |  |  | 
278  |  |     /* allocate a buffer which can hold the entire derived secret. */  | 
279  | 0  |     secret = PORT_Alloc(len);  | 
280  | 0  |     if (secret == NULL) { | 
281  | 0  |         err = MP_MEM;  | 
282  | 0  |         goto cleanup;  | 
283  | 0  |     }  | 
284  |  |     /* grab the derived secret */  | 
285  | 0  |     err = mp_to_unsigned_octets(&ZZ, secret, len);  | 
286  | 0  |     if (err >= 0)  | 
287  | 0  |         err = MP_OKAY;  | 
288  |  |     /*  | 
289  |  |     ** if outBytes is 0 take all of the bytes from the derived secret.  | 
290  |  |     ** if outBytes is not 0 take exactly outBytes from the derived secret, zero  | 
291  |  |     ** pad at the beginning if necessary, and truncate beginning bytes  | 
292  |  |     ** if necessary.  | 
293  |  |     */  | 
294  | 0  |     if (outBytes > 0)  | 
295  | 0  |         nb = outBytes;  | 
296  | 0  |     else  | 
297  | 0  |         nb = len;  | 
298  | 0  |     if (SECITEM_AllocItem(NULL, derivedSecret, nb) == NULL) { | 
299  | 0  |         err = MP_MEM;  | 
300  | 0  |         goto cleanup;  | 
301  | 0  |     }  | 
302  | 0  |     if (len < nb) { | 
303  | 0  |         unsigned int offset = nb - len;  | 
304  | 0  |         memset(derivedSecret->data, 0, offset);  | 
305  | 0  |         memcpy(derivedSecret->data + offset, secret, len);  | 
306  | 0  |     } else { | 
307  | 0  |         memcpy(derivedSecret->data, secret + len - nb, nb);  | 
308  | 0  |     }  | 
309  | 0  | cleanup:  | 
310  | 0  |     mp_clear(&p);  | 
311  | 0  |     mp_clear(&Xa);  | 
312  | 0  |     mp_clear(&Yb);  | 
313  | 0  |     mp_clear(&ZZ);  | 
314  | 0  |     mp_clear(&psub1);  | 
315  | 0  |     if (secret) { | 
316  |  |         /* free the buffer allocated for the full secret. */  | 
317  | 0  |         PORT_ZFree(secret, len);  | 
318  | 0  |     }  | 
319  | 0  |     if (err) { | 
320  | 0  |         MP_TO_SEC_ERROR(err);  | 
321  | 0  |         if (derivedSecret->data)  | 
322  | 0  |             PORT_ZFree(derivedSecret->data, derivedSecret->len);  | 
323  | 0  |         return SECFailure;  | 
324  | 0  |     }  | 
325  | 0  |     return SECSuccess;  | 
326  | 0  | }  | 
327  |  |  | 
328  |  | SECStatus  | 
329  |  | KEA_Derive(SECItem *prime,  | 
330  |  |            SECItem *public1,  | 
331  |  |            SECItem *public2,  | 
332  |  |            SECItem *private1,  | 
333  |  |            SECItem *private2,  | 
334  |  |            SECItem *derivedSecret)  | 
335  | 0  | { | 
336  | 0  |     mp_int p, Y, R, r, x, t, u, w;  | 
337  | 0  |     mp_err err;  | 
338  | 0  |     unsigned char *secret = NULL;  | 
339  | 0  |     unsigned int len = 0, offset;  | 
340  | 0  |     if (!prime || !public1 || !public2 || !private1 || !private2 ||  | 
341  | 0  |         !derivedSecret) { | 
342  | 0  |         PORT_SetError(SEC_ERROR_INVALID_ARGS);  | 
343  | 0  |         return SECFailure;  | 
344  | 0  |     }  | 
345  | 0  |     memset(derivedSecret, 0, sizeof *derivedSecret);  | 
346  | 0  |     MP_DIGITS(&p) = 0;  | 
347  | 0  |     MP_DIGITS(&Y) = 0;  | 
348  | 0  |     MP_DIGITS(&R) = 0;  | 
349  | 0  |     MP_DIGITS(&r) = 0;  | 
350  | 0  |     MP_DIGITS(&x) = 0;  | 
351  | 0  |     MP_DIGITS(&t) = 0;  | 
352  | 0  |     MP_DIGITS(&u) = 0;  | 
353  | 0  |     MP_DIGITS(&w) = 0;  | 
354  | 0  |     CHECK_MPI_OK(mp_init(&p));  | 
355  | 0  |     CHECK_MPI_OK(mp_init(&Y));  | 
356  | 0  |     CHECK_MPI_OK(mp_init(&R));  | 
357  | 0  |     CHECK_MPI_OK(mp_init(&r));  | 
358  | 0  |     CHECK_MPI_OK(mp_init(&x));  | 
359  | 0  |     CHECK_MPI_OK(mp_init(&t));  | 
360  | 0  |     CHECK_MPI_OK(mp_init(&u));  | 
361  | 0  |     CHECK_MPI_OK(mp_init(&w));  | 
362  | 0  |     SECITEM_TO_MPINT(*prime, &p);  | 
363  | 0  |     SECITEM_TO_MPINT(*public1, &Y);  | 
364  | 0  |     SECITEM_TO_MPINT(*public2, &R);  | 
365  | 0  |     SECITEM_TO_MPINT(*private1, &r);  | 
366  | 0  |     SECITEM_TO_MPINT(*private2, &x);  | 
367  |  |     /* t = DH(Y, r, p) = Y ** r mod p */  | 
368  | 0  |     CHECK_MPI_OK(mp_exptmod(&Y, &r, &p, &t));  | 
369  |  |     /* u = DH(R, x, p) = R ** x mod p */  | 
370  | 0  |     CHECK_MPI_OK(mp_exptmod(&R, &x, &p, &u));  | 
371  |  |     /* w = (t + u) mod p */  | 
372  | 0  |     CHECK_MPI_OK(mp_addmod(&t, &u, &p, &w));  | 
373  |  |     /* allocate a buffer for the full derived secret */  | 
374  | 0  |     len = mp_unsigned_octet_size(&w);  | 
375  | 0  |     secret = PORT_Alloc(len);  | 
376  | 0  |     if (secret == NULL) { | 
377  | 0  |         err = MP_MEM;  | 
378  | 0  |         goto cleanup;  | 
379  | 0  |     }  | 
380  |  |     /* grab the secret */  | 
381  | 0  |     err = mp_to_unsigned_octets(&w, secret, len);  | 
382  | 0  |     if (err > 0)  | 
383  | 0  |         err = MP_OKAY;  | 
384  |  |     /* allocate output buffer */  | 
385  | 0  |     if (SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN) == NULL) { | 
386  | 0  |         err = MP_MEM;  | 
387  | 0  |         goto cleanup;  | 
388  | 0  |     }  | 
389  | 0  |     memset(derivedSecret->data, 0, derivedSecret->len);  | 
390  |  |     /* copy in the 128 lsb of the secret */  | 
391  | 0  |     if (len >= KEA_DERIVED_SECRET_LEN) { | 
392  | 0  |         memcpy(derivedSecret->data, secret + (len - KEA_DERIVED_SECRET_LEN),  | 
393  | 0  |                KEA_DERIVED_SECRET_LEN);  | 
394  | 0  |     } else { | 
395  | 0  |         offset = KEA_DERIVED_SECRET_LEN - len;  | 
396  | 0  |         memcpy(derivedSecret->data + offset, secret, len);  | 
397  | 0  |     }  | 
398  | 0  | cleanup:  | 
399  | 0  |     mp_clear(&p);  | 
400  | 0  |     mp_clear(&Y);  | 
401  | 0  |     mp_clear(&R);  | 
402  | 0  |     mp_clear(&r);  | 
403  | 0  |     mp_clear(&x);  | 
404  | 0  |     mp_clear(&t);  | 
405  | 0  |     mp_clear(&u);  | 
406  | 0  |     mp_clear(&w);  | 
407  | 0  |     if (secret)  | 
408  | 0  |         PORT_ZFree(secret, len);  | 
409  | 0  |     if (err) { | 
410  | 0  |         MP_TO_SEC_ERROR(err);  | 
411  | 0  |         if (derivedSecret->data)  | 
412  | 0  |             PORT_ZFree(derivedSecret->data, derivedSecret->len);  | 
413  | 0  |         return SECFailure;  | 
414  | 0  |     }  | 
415  | 0  |     return SECSuccess;  | 
416  | 0  | }  | 
417  |  |  | 
418  |  | /* Test counts based on the fact the prime and subprime  | 
419  |  |  * were given to us */  | 
420  |  | static int  | 
421  |  | dh_prime_testcount(int prime_length)  | 
422  | 0  | { | 
423  | 0  |     if (prime_length < 1024) { | 
424  | 0  |         return 50;  | 
425  | 0  |     } else if (prime_length < 2048) { | 
426  | 0  |         return 40;  | 
427  | 0  |     } else if (prime_length < 3072) { | 
428  | 0  |         return 56;  | 
429  | 0  |     }  | 
430  | 0  |     return 64;  | 
431  | 0  | }  | 
432  |  |  | 
433  |  | PRBool  | 
434  |  | KEA_PrimeCheck(SECItem *prime)  | 
435  | 0  | { | 
436  | 0  |     mp_int p;  | 
437  | 0  |     mp_err err = 0;  | 
438  | 0  |     MP_DIGITS(&p) = 0;  | 
439  | 0  |     CHECK_MPI_OK(mp_init(&p));  | 
440  | 0  |     SECITEM_TO_MPINT(*prime, &p);  | 
441  | 0  |     CHECK_MPI_OK(mpp_pprime_secure(&p, dh_prime_testcount(prime->len)));  | 
442  | 0  | cleanup:  | 
443  | 0  |     mp_clear(&p);  | 
444  | 0  |     return err ? PR_FALSE : PR_TRUE;  | 
445  | 0  | }  | 
446  |  |  | 
447  |  | PRBool  | 
448  |  | KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)  | 
449  | 0  | { | 
450  | 0  |     mp_int p, q, y, r, psub1;  | 
451  | 0  |     mp_err err;  | 
452  | 0  |     int cmp = 1; /* default is false */  | 
453  | 0  |     if (!Y || !prime || !subPrime) { | 
454  | 0  |         PORT_SetError(SEC_ERROR_INVALID_ARGS);  | 
455  | 0  |         return SECFailure;  | 
456  | 0  |     }  | 
457  | 0  |     MP_DIGITS(&p) = 0;  | 
458  | 0  |     MP_DIGITS(&q) = 0;  | 
459  | 0  |     MP_DIGITS(&y) = 0;  | 
460  | 0  |     MP_DIGITS(&r) = 0;  | 
461  | 0  |     MP_DIGITS(&psub1) = 0;  | 
462  | 0  |     CHECK_MPI_OK(mp_init(&p));  | 
463  | 0  |     CHECK_MPI_OK(mp_init(&q));  | 
464  | 0  |     CHECK_MPI_OK(mp_init(&y));  | 
465  | 0  |     CHECK_MPI_OK(mp_init(&r));  | 
466  | 0  |     CHECK_MPI_OK(mp_init(&psub1));  | 
467  | 0  |     SECITEM_TO_MPINT(*prime, &p);  | 
468  | 0  |     SECITEM_TO_MPINT(*subPrime, &q);  | 
469  | 0  |     SECITEM_TO_MPINT(*Y, &y);  | 
470  | 0  |     CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));  | 
471  |  |     /*  | 
472  |  |      * We check that the public value isn't zero (which isn't in the  | 
473  |  |      * group), one (subgroup of order one) or p-1 (subgroup of order 2). We  | 
474  |  |      * also check that the public value is less than p, to avoid being fooled  | 
475  |  |      * by values like p+1 or 2*p-1.  | 
476  |  |      * This check is required by SP-800-56Ar3. It's also done in derive,  | 
477  |  |      * but this is only called in various FIPS cases, so put it here to help  | 
478  |  |      * reviewers find it.  | 
479  |  |      */  | 
480  | 0  |     if (mp_cmp_d(&y, 1) <= 0 ||  | 
481  | 0  |         mp_cmp(&y, &psub1) >= 0) { | 
482  | 0  |         err = MP_BADARG;  | 
483  | 0  |         goto cleanup;  | 
484  | 0  |     }  | 
485  |  |     /* compute r = y**q mod p */  | 
486  | 0  |     CHECK_MPI_OK(mp_exptmod(&y, &q, &p, &r));  | 
487  |  |     /* compare to 1 */  | 
488  | 0  |     cmp = mp_cmp_d(&r, 1);  | 
489  | 0  | cleanup:  | 
490  | 0  |     mp_clear(&p);  | 
491  | 0  |     mp_clear(&q);  | 
492  | 0  |     mp_clear(&y);  | 
493  | 0  |     mp_clear(&r);  | 
494  | 0  |     mp_clear(&psub1);  | 
495  | 0  |     if (err) { | 
496  | 0  |         MP_TO_SEC_ERROR(err);  | 
497  | 0  |         return PR_FALSE;  | 
498  | 0  |     }  | 
499  | 0  |     return (cmp == 0) ? PR_TRUE : PR_FALSE;  | 
500  | 0  | }  |