/src/nss/lib/softoken/jpakesftk.c
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  |  | #include "seccomon.h"  | 
6  |  | #include "secerr.h"  | 
7  |  | #include "blapi.h"  | 
8  |  | #include "pkcs11i.h"  | 
9  |  | #include "softoken.h"  | 
10  |  |  | 
11  |  | static CK_RV  | 
12  |  | jpake_mapStatus(SECStatus rv, CK_RV invalidArgsMapping)  | 
13  | 0  | { | 
14  | 0  |     int err;  | 
15  | 0  |     if (rv == SECSuccess)  | 
16  | 0  |         return CKR_OK;  | 
17  | 0  |     err = PORT_GetError();  | 
18  | 0  |     switch (err) { | 
19  |  |         /* XXX: SEC_ERROR_INVALID_ARGS might be caused by invalid template  | 
20  |  |             parameters. */  | 
21  | 0  |         case SEC_ERROR_INVALID_ARGS:  | 
22  | 0  |             return invalidArgsMapping;  | 
23  | 0  |         case SEC_ERROR_BAD_SIGNATURE:  | 
24  | 0  |             return CKR_SIGNATURE_INVALID;  | 
25  | 0  |         case SEC_ERROR_NO_MEMORY:  | 
26  | 0  |             return CKR_HOST_MEMORY;  | 
27  | 0  |     }  | 
28  | 0  |     return CKR_FUNCTION_FAILED;  | 
29  | 0  | }  | 
30  |  |  | 
31  |  | /* If key is not NULL then the gx value will be stored as an attribute with  | 
32  |  |    the type given by the gxAttrType parameter. */  | 
33  |  | static CK_RV  | 
34  |  | jpake_Sign(PLArenaPool *arena, const PQGParams *pqg, HASH_HashType hashType,  | 
35  |  |            const SECItem *signerID, const SECItem *x,  | 
36  |  |            CK_NSS_JPAKEPublicValue *out)  | 
37  | 0  | { | 
38  | 0  |     SECItem gx, gv, r;  | 
39  | 0  |     CK_RV crv;  | 
40  |  | 
  | 
41  | 0  |     PORT_Assert(arena != NULL);  | 
42  |  | 
  | 
43  | 0  |     gx.data = NULL;  | 
44  | 0  |     gv.data = NULL;  | 
45  | 0  |     r.data = NULL;  | 
46  | 0  |     crv = jpake_mapStatus(JPAKE_Sign(arena, pqg, hashType, signerID, x, NULL,  | 
47  | 0  |                                      NULL, &gx, &gv, &r),  | 
48  | 0  |                           CKR_MECHANISM_PARAM_INVALID);  | 
49  | 0  |     if (crv == CKR_OK) { | 
50  | 0  |         if ((out->pGX != NULL && out->ulGXLen >= gx.len) &&  | 
51  | 0  |             (out->pGV != NULL && out->ulGVLen >= gv.len) &&  | 
52  | 0  |             (out->pR != NULL && out->ulRLen >= r.len)) { | 
53  | 0  |             PORT_Memcpy(out->pGX, gx.data, gx.len);  | 
54  | 0  |             PORT_Memcpy(out->pGV, gv.data, gv.len);  | 
55  | 0  |             PORT_Memcpy(out->pR, r.data, r.len);  | 
56  | 0  |             out->ulGXLen = gx.len;  | 
57  | 0  |             out->ulGVLen = gv.len;  | 
58  | 0  |             out->ulRLen = r.len;  | 
59  | 0  |         } else { | 
60  | 0  |             crv = CKR_MECHANISM_PARAM_INVALID;  | 
61  | 0  |         }  | 
62  | 0  |     }  | 
63  | 0  |     return crv;  | 
64  | 0  | }  | 
65  |  |  | 
66  |  | static CK_RV  | 
67  |  | jpake_Verify(PLArenaPool *arena, const PQGParams *pqg,  | 
68  |  |              HASH_HashType hashType, const SECItem *signerID,  | 
69  |  |              const CK_BYTE *peerIDData, CK_ULONG peerIDLen,  | 
70  |  |              const CK_NSS_JPAKEPublicValue *publicValueIn)  | 
71  | 0  | { | 
72  | 0  |     SECItem peerID, gx, gv, r;  | 
73  | 0  |     peerID.data = (unsigned char *)peerIDData;  | 
74  | 0  |     peerID.len = peerIDLen;  | 
75  | 0  |     gx.data = publicValueIn->pGX;  | 
76  | 0  |     gx.len = publicValueIn->ulGXLen;  | 
77  | 0  |     gv.data = publicValueIn->pGV;  | 
78  | 0  |     gv.len = publicValueIn->ulGVLen;  | 
79  | 0  |     r.data = publicValueIn->pR;  | 
80  | 0  |     r.len = publicValueIn->ulRLen;  | 
81  | 0  |     return jpake_mapStatus(JPAKE_Verify(arena, pqg, hashType, signerID, &peerID,  | 
82  | 0  |                                         &gx, &gv, &r),  | 
83  | 0  |                            CKR_MECHANISM_PARAM_INVALID);  | 
84  | 0  | }  | 
85  |  |  | 
86  | 0  | #define NUM_ELEM(x) (sizeof(x) / sizeof(x)[0])  | 
87  |  |  | 
88  |  | /* If the template has the key type set, ensure that it was set to the correct  | 
89  |  |  * value. If the template did not have the key type set, set it to the  | 
90  |  |  * correct value.  | 
91  |  |  */  | 
92  |  | static CK_RV  | 
93  |  | jpake_enforceKeyType(SFTKObject *key, CK_KEY_TYPE keyType)  | 
94  | 0  | { | 
95  | 0  |     CK_RV crv;  | 
96  | 0  |     SFTKAttribute *keyTypeAttr = sftk_FindAttribute(key, CKA_KEY_TYPE);  | 
97  | 0  |     if (keyTypeAttr != NULL) { | 
98  | 0  |         crv = *(CK_KEY_TYPE *)keyTypeAttr->attrib.pValue == keyType  | 
99  | 0  |                   ? CKR_OK  | 
100  | 0  |                   : CKR_TEMPLATE_INCONSISTENT;  | 
101  | 0  |         sftk_FreeAttribute(keyTypeAttr);  | 
102  | 0  |     } else { | 
103  | 0  |         crv = sftk_forceAttribute(key, CKA_KEY_TYPE, &keyType, sizeof keyType);  | 
104  | 0  |     }  | 
105  | 0  |     return crv;  | 
106  | 0  | }  | 
107  |  |  | 
108  |  | static CK_RV  | 
109  |  | jpake_MultipleSecItem2Attribute(SFTKObject *key, const SFTKItemTemplate *attrs,  | 
110  |  |                                 size_t attrsCount)  | 
111  | 0  | { | 
112  | 0  |     size_t i;  | 
113  |  | 
  | 
114  | 0  |     for (i = 0; i < attrsCount; ++i) { | 
115  | 0  |         CK_RV crv = sftk_forceAttribute(key, attrs[i].type, attrs[i].item->data,  | 
116  | 0  |                                         attrs[i].item->len);  | 
117  | 0  |         if (crv != CKR_OK)  | 
118  | 0  |             return crv;  | 
119  | 0  |     }  | 
120  | 0  |     return CKR_OK;  | 
121  | 0  | }  | 
122  |  |  | 
123  |  | CK_RV  | 
124  |  | jpake_Round1(HASH_HashType hashType, CK_NSS_JPAKERound1Params *params,  | 
125  |  |              SFTKObject *key)  | 
126  | 0  | { | 
127  | 0  |     CK_RV crv;  | 
128  | 0  |     PQGParams pqg;  | 
129  | 0  |     PLArenaPool *arena;  | 
130  | 0  |     SECItem signerID;  | 
131  | 0  |     SFTKItemTemplate templateAttrs[] = { | 
132  | 0  |         { CKA_PRIME, &pqg.prime }, | 
133  | 0  |         { CKA_SUBPRIME, &pqg.subPrime }, | 
134  | 0  |         { CKA_BASE, &pqg.base }, | 
135  | 0  |         { CKA_NSS_JPAKE_SIGNERID, &signerID } | 
136  | 0  |     };  | 
137  | 0  |     SECItem x2, gx1, gx2;  | 
138  | 0  |     const SFTKItemTemplate generatedAttrs[] = { | 
139  | 0  |         { CKA_NSS_JPAKE_X2, &x2 }, | 
140  | 0  |         { CKA_NSS_JPAKE_GX1, &gx1 }, | 
141  | 0  |         { CKA_NSS_JPAKE_GX2, &gx2 }, | 
142  | 0  |     };  | 
143  | 0  |     SECItem x1;  | 
144  |  | 
  | 
145  | 0  |     PORT_Assert(params != NULL);  | 
146  | 0  |     PORT_Assert(key != NULL);  | 
147  |  | 
  | 
148  | 0  |     arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE);  | 
149  | 0  |     if (arena == NULL)  | 
150  | 0  |         crv = CKR_HOST_MEMORY;  | 
151  |  | 
  | 
152  | 0  |     crv = sftk_MultipleAttribute2SecItem(arena, key, templateAttrs,  | 
153  | 0  |                                          NUM_ELEM(templateAttrs));  | 
154  |  | 
  | 
155  | 0  |     if (crv == CKR_OK && (signerID.data == NULL || signerID.len == 0))  | 
156  | 0  |         crv = CKR_TEMPLATE_INCOMPLETE;  | 
157  |  |  | 
158  |  |     /* generate x1, g^x1 and the proof of knowledge of x1 */  | 
159  | 0  |     if (crv == CKR_OK) { | 
160  | 0  |         x1.data = NULL;  | 
161  | 0  |         crv = jpake_mapStatus(DSA_NewRandom(arena, &pqg.subPrime, &x1),  | 
162  | 0  |                               CKR_TEMPLATE_INCONSISTENT);  | 
163  | 0  |     }  | 
164  | 0  |     if (crv == CKR_OK)  | 
165  | 0  |         crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x1, ¶ms->gx1);  | 
166  |  |  | 
167  |  |     /* generate x2, g^x2 and the proof of knowledge of x2 */  | 
168  | 0  |     if (crv == CKR_OK) { | 
169  | 0  |         x2.data = NULL;  | 
170  | 0  |         crv = jpake_mapStatus(DSA_NewRandom(arena, &pqg.subPrime, &x2),  | 
171  | 0  |                               CKR_TEMPLATE_INCONSISTENT);  | 
172  | 0  |     }  | 
173  | 0  |     if (crv == CKR_OK)  | 
174  | 0  |         crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x2, ¶ms->gx2);  | 
175  |  |  | 
176  |  |     /* Save the values needed for round 2 into CKA_VALUE */  | 
177  | 0  |     if (crv == CKR_OK) { | 
178  | 0  |         gx1.data = params->gx1.pGX;  | 
179  | 0  |         gx1.len = params->gx1.ulGXLen;  | 
180  | 0  |         gx2.data = params->gx2.pGX;  | 
181  | 0  |         gx2.len = params->gx2.ulGXLen;  | 
182  | 0  |         crv = jpake_MultipleSecItem2Attribute(key, generatedAttrs,  | 
183  | 0  |                                               NUM_ELEM(generatedAttrs));  | 
184  | 0  |     }  | 
185  |  | 
  | 
186  | 0  |     PORT_FreeArena(arena, PR_TRUE);  | 
187  | 0  |     return crv;  | 
188  | 0  | }  | 
189  |  |  | 
190  |  | CK_RV  | 
191  |  | jpake_Round2(HASH_HashType hashType, CK_NSS_JPAKERound2Params *params,  | 
192  |  |              SFTKObject *sourceKey, SFTKObject *key)  | 
193  | 0  | { | 
194  | 0  |     CK_RV crv;  | 
195  | 0  |     PLArenaPool *arena;  | 
196  | 0  |     PQGParams pqg;  | 
197  | 0  |     SECItem signerID, x2, gx1, gx2;  | 
198  | 0  |     SFTKItemTemplate sourceAttrs[] = { | 
199  | 0  |         { CKA_PRIME, &pqg.prime }, | 
200  | 0  |         { CKA_SUBPRIME, &pqg.subPrime }, | 
201  | 0  |         { CKA_BASE, &pqg.base }, | 
202  | 0  |         { CKA_NSS_JPAKE_SIGNERID, &signerID }, | 
203  | 0  |         { CKA_NSS_JPAKE_X2, &x2 }, | 
204  | 0  |         { CKA_NSS_JPAKE_GX1, &gx1 }, | 
205  | 0  |         { CKA_NSS_JPAKE_GX2, &gx2 }, | 
206  | 0  |     };  | 
207  | 0  |     SECItem x2s, gx3, gx4;  | 
208  | 0  |     const SFTKItemTemplate copiedAndGeneratedAttrs[] = { | 
209  | 0  |         { CKA_NSS_JPAKE_SIGNERID, &signerID }, | 
210  | 0  |         { CKA_PRIME, &pqg.prime }, | 
211  | 0  |         { CKA_SUBPRIME, &pqg.subPrime }, | 
212  | 0  |         { CKA_NSS_JPAKE_X2, &x2 }, | 
213  | 0  |         { CKA_NSS_JPAKE_X2S, &x2s }, | 
214  | 0  |         { CKA_NSS_JPAKE_GX1, &gx1 }, | 
215  | 0  |         { CKA_NSS_JPAKE_GX2, &gx2 }, | 
216  | 0  |         { CKA_NSS_JPAKE_GX3, &gx3 }, | 
217  | 0  |         { CKA_NSS_JPAKE_GX4, &gx4 } | 
218  | 0  |     };  | 
219  | 0  |     SECItem peerID;  | 
220  |  | 
  | 
221  | 0  |     PORT_Assert(params != NULL);  | 
222  | 0  |     PORT_Assert(sourceKey != NULL);  | 
223  | 0  |     PORT_Assert(key != NULL);  | 
224  |  | 
  | 
225  | 0  |     arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE);  | 
226  | 0  |     if (arena == NULL)  | 
227  | 0  |         crv = CKR_HOST_MEMORY;  | 
228  |  |  | 
229  |  |     /* TODO: check CKK_NSS_JPAKE_ROUND1 */  | 
230  |  | 
  | 
231  | 0  |     crv = sftk_MultipleAttribute2SecItem(arena, sourceKey, sourceAttrs,  | 
232  | 0  |                                          NUM_ELEM(sourceAttrs));  | 
233  |  |  | 
234  |  |     /* Get the peer's ID out of the template and sanity-check it. */  | 
235  | 0  |     if (crv == CKR_OK)  | 
236  | 0  |         crv = sftk_Attribute2SecItem(arena, &peerID, key,  | 
237  | 0  |                                      CKA_NSS_JPAKE_PEERID);  | 
238  | 0  |     if (crv == CKR_OK && (peerID.data == NULL || peerID.len == 0))  | 
239  | 0  |         crv = CKR_TEMPLATE_INCOMPLETE;  | 
240  | 0  |     if (crv == CKR_OK && SECITEM_CompareItem(&signerID, &peerID) == SECEqual)  | 
241  | 0  |         crv = CKR_TEMPLATE_INCONSISTENT;  | 
242  |  |  | 
243  |  |     /* Verify zero-knowledge proofs for g^x3 and g^x4 */  | 
244  | 0  |     if (crv == CKR_OK)  | 
245  | 0  |         crv = jpake_Verify(arena, &pqg, hashType, &signerID,  | 
246  | 0  |                            peerID.data, peerID.len, ¶ms->gx3);  | 
247  | 0  |     if (crv == CKR_OK)  | 
248  | 0  |         crv = jpake_Verify(arena, &pqg, hashType, &signerID,  | 
249  | 0  |                            peerID.data, peerID.len, ¶ms->gx4);  | 
250  |  |  | 
251  |  |     /* Calculate the base and x2s for A=base^x2s */  | 
252  | 0  |     if (crv == CKR_OK) { | 
253  | 0  |         SECItem s;  | 
254  | 0  |         s.data = params->pSharedKey;  | 
255  | 0  |         s.len = params->ulSharedKeyLen;  | 
256  | 0  |         gx3.data = params->gx3.pGX;  | 
257  | 0  |         gx3.len = params->gx3.ulGXLen;  | 
258  | 0  |         gx4.data = params->gx4.pGX;  | 
259  | 0  |         gx4.len = params->gx4.ulGXLen;  | 
260  | 0  |         pqg.base.data = NULL;  | 
261  | 0  |         x2s.data = NULL;  | 
262  | 0  |         crv = jpake_mapStatus(JPAKE_Round2(arena, &pqg.prime, &pqg.subPrime,  | 
263  | 0  |                                            &gx1, &gx3, &gx4, &pqg.base,  | 
264  | 0  |                                            &x2, &s, &x2s),  | 
265  | 0  |                               CKR_MECHANISM_PARAM_INVALID);  | 
266  | 0  |     }  | 
267  |  |  | 
268  |  |     /* Generate A=base^x2s and its zero-knowledge proof. */  | 
269  | 0  |     if (crv == CKR_OK)  | 
270  | 0  |         crv = jpake_Sign(arena, &pqg, hashType, &signerID, &x2s, ¶ms->A);  | 
271  |  |  | 
272  |  |     /* Copy P and Q from the ROUND1 key to the ROUND2 key and save the values  | 
273  |  |        needed for the final key material derivation into CKA_VALUE. */  | 
274  | 0  |     if (crv == CKR_OK)  | 
275  | 0  |         crv = sftk_forceAttribute(key, CKA_PRIME, pqg.prime.data,  | 
276  | 0  |                                   pqg.prime.len);  | 
277  | 0  |     if (crv == CKR_OK)  | 
278  | 0  |         crv = sftk_forceAttribute(key, CKA_SUBPRIME, pqg.subPrime.data,  | 
279  | 0  |                                   pqg.subPrime.len);  | 
280  | 0  |     if (crv == CKR_OK) { | 
281  | 0  |         crv = jpake_MultipleSecItem2Attribute(key, copiedAndGeneratedAttrs,  | 
282  | 0  |                                               NUM_ELEM(copiedAndGeneratedAttrs));  | 
283  | 0  |     }  | 
284  |  | 
  | 
285  | 0  |     if (crv == CKR_OK)  | 
286  | 0  |         crv = jpake_enforceKeyType(key, CKK_NSS_JPAKE_ROUND2);  | 
287  |  | 
  | 
288  | 0  |     PORT_FreeArena(arena, PR_TRUE);  | 
289  | 0  |     return crv;  | 
290  | 0  | }  | 
291  |  |  | 
292  |  | CK_RV  | 
293  |  | jpake_Final(HASH_HashType hashType, const CK_NSS_JPAKEFinalParams *param,  | 
294  |  |             SFTKObject *sourceKey, SFTKObject *key)  | 
295  | 0  | { | 
296  | 0  |     PLArenaPool *arena;  | 
297  | 0  |     SECItem K;  | 
298  | 0  |     PQGParams pqg;  | 
299  | 0  |     CK_RV crv;  | 
300  | 0  |     SECItem peerID, signerID, x2s, x2, gx1, gx2, gx3, gx4;  | 
301  | 0  |     SFTKItemTemplate sourceAttrs[] = { | 
302  | 0  |         { CKA_NSS_JPAKE_PEERID, &peerID }, | 
303  | 0  |         { CKA_NSS_JPAKE_SIGNERID, &signerID }, | 
304  | 0  |         { CKA_PRIME, &pqg.prime }, | 
305  | 0  |         { CKA_SUBPRIME, &pqg.subPrime }, | 
306  | 0  |         { CKA_NSS_JPAKE_X2, &x2 }, | 
307  | 0  |         { CKA_NSS_JPAKE_X2S, &x2s }, | 
308  | 0  |         { CKA_NSS_JPAKE_GX1, &gx1 }, | 
309  | 0  |         { CKA_NSS_JPAKE_GX2, &gx2 }, | 
310  | 0  |         { CKA_NSS_JPAKE_GX3, &gx3 }, | 
311  | 0  |         { CKA_NSS_JPAKE_GX4, &gx4 } | 
312  | 0  |     };  | 
313  |  | 
  | 
314  | 0  |     PORT_Assert(param != NULL);  | 
315  | 0  |     PORT_Assert(sourceKey != NULL);  | 
316  | 0  |     PORT_Assert(key != NULL);  | 
317  |  | 
  | 
318  | 0  |     arena = PORT_NewArena(NSS_SOFTOKEN_DEFAULT_CHUNKSIZE);  | 
319  | 0  |     if (arena == NULL)  | 
320  | 0  |         crv = CKR_HOST_MEMORY;  | 
321  |  |  | 
322  |  |     /* TODO: verify key type CKK_NSS_JPAKE_ROUND2 */  | 
323  |  | 
  | 
324  | 0  |     crv = sftk_MultipleAttribute2SecItem(arena, sourceKey, sourceAttrs,  | 
325  | 0  |                                          NUM_ELEM(sourceAttrs));  | 
326  |  |  | 
327  |  |     /* Calculate base for B=base^x4s */  | 
328  | 0  |     if (crv == CKR_OK) { | 
329  | 0  |         pqg.base.data = NULL;  | 
330  | 0  |         crv = jpake_mapStatus(JPAKE_Round2(arena, &pqg.prime, &pqg.subPrime,  | 
331  | 0  |                                            &gx1, &gx2, &gx3, &pqg.base,  | 
332  | 0  |                                            NULL, NULL, NULL),  | 
333  | 0  |                               CKR_MECHANISM_PARAM_INVALID);  | 
334  | 0  |     }  | 
335  |  |  | 
336  |  |     /* Verify zero-knowledge proof for B */  | 
337  | 0  |     if (crv == CKR_OK)  | 
338  | 0  |         crv = jpake_Verify(arena, &pqg, hashType, &signerID,  | 
339  | 0  |                            peerID.data, peerID.len, ¶m->B);  | 
340  | 0  |     if (crv == CKR_OK) { | 
341  | 0  |         SECItem B;  | 
342  | 0  |         B.data = param->B.pGX;  | 
343  | 0  |         B.len = param->B.ulGXLen;  | 
344  | 0  |         K.data = NULL;  | 
345  | 0  |         crv = jpake_mapStatus(JPAKE_Final(arena, &pqg.prime, &pqg.subPrime,  | 
346  | 0  |                                           &x2, &gx4, &x2s, &B, &K),  | 
347  | 0  |                               CKR_MECHANISM_PARAM_INVALID);  | 
348  | 0  |     }  | 
349  |  |  | 
350  |  |     /* Save key material into CKA_VALUE. */  | 
351  | 0  |     if (crv == CKR_OK)  | 
352  | 0  |         crv = sftk_forceAttribute(key, CKA_VALUE, K.data, K.len);  | 
353  |  | 
  | 
354  | 0  |     if (crv == CKR_OK)  | 
355  | 0  |         crv = jpake_enforceKeyType(key, CKK_GENERIC_SECRET);  | 
356  |  | 
  | 
357  | 0  |     PORT_FreeArena(arena, PR_TRUE);  | 
358  | 0  |     return crv;  | 
359  | 0  | }  |