/src/nss/lib/softoken/lowpbe.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 "plarena.h" |
6 | | |
7 | | #include "seccomon.h" |
8 | | #include "secitem.h" |
9 | | #include "secport.h" |
10 | | #include "hasht.h" |
11 | | #include "pkcs11t.h" |
12 | | #include "blapi.h" |
13 | | #include "hasht.h" |
14 | | #include "secasn1.h" |
15 | | #include "secder.h" |
16 | | #include "lowpbe.h" |
17 | | #include "secoid.h" |
18 | | #include "alghmac.h" |
19 | | #include "softoken.h" |
20 | | #include "secerr.h" |
21 | | #include "pkcs11i.h" |
22 | | |
23 | | SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
24 | | |
25 | | /* how much a crypto encrypt/decryption may expand a buffer */ |
26 | 0 | #define MAX_CRYPTO_EXPANSION 64 |
27 | | |
28 | | /* template for PKCS 5 PBE Parameter. This template has been expanded |
29 | | * based upon the additions in PKCS 12. This should eventually be moved |
30 | | * if RSA updates PKCS 5. |
31 | | */ |
32 | | static const SEC_ASN1Template NSSPKCS5PBEParameterTemplate[] = { |
33 | | { SEC_ASN1_SEQUENCE, |
34 | | 0, NULL, sizeof(NSSPKCS5PBEParameter) }, |
35 | | { SEC_ASN1_OCTET_STRING, |
36 | | offsetof(NSSPKCS5PBEParameter, salt) }, |
37 | | { SEC_ASN1_INTEGER, |
38 | | offsetof(NSSPKCS5PBEParameter, iteration) }, |
39 | | { 0 } |
40 | | }; |
41 | | |
42 | | static const SEC_ASN1Template NSSPKCS5PKCS12V2PBEParameterTemplate[] = { |
43 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) }, |
44 | | { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) }, |
45 | | { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) }, |
46 | | { 0 } |
47 | | }; |
48 | | |
49 | | /* PKCS5 v2 */ |
50 | | |
51 | | struct nsspkcs5V2PBEParameterStr { |
52 | | SECAlgorithmID keyParams; /* parameters of the key generation */ |
53 | | SECAlgorithmID algParams; /* parameters for the encryption or mac op */ |
54 | | }; |
55 | | |
56 | | typedef struct nsspkcs5V2PBEParameterStr nsspkcs5V2PBEParameter; |
57 | | |
58 | | static const SEC_ASN1Template NSSPKCS5V2PBES2ParameterTemplate[] = { |
59 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(nsspkcs5V2PBEParameter) }, |
60 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
61 | | offsetof(nsspkcs5V2PBEParameter, keyParams), |
62 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
63 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
64 | | offsetof(nsspkcs5V2PBEParameter, algParams), |
65 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
66 | | { 0 } |
67 | | }; |
68 | | |
69 | | static const SEC_ASN1Template NSSPKCS5V2PBEParameterTemplate[] = { |
70 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSPKCS5PBEParameter) }, |
71 | | /* this is really a choice, but since we don't understand any other |
72 | | * choice, just inline it. */ |
73 | | { SEC_ASN1_OCTET_STRING, offsetof(NSSPKCS5PBEParameter, salt) }, |
74 | | { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, iteration) }, |
75 | | { SEC_ASN1_INTEGER, offsetof(NSSPKCS5PBEParameter, keyLength) }, |
76 | | { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
77 | | offsetof(NSSPKCS5PBEParameter, prfAlg), |
78 | | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
79 | | { 0 } |
80 | | }; |
81 | | |
82 | | SECStatus |
83 | | nsspkcs5_HashBuf(const SECHashObject *hashObj, unsigned char *dest, |
84 | | unsigned char *src, int len) |
85 | 0 | { |
86 | 0 | void *ctx; |
87 | 0 | unsigned int retLen; |
88 | |
|
89 | 0 | ctx = hashObj->create(); |
90 | 0 | if (ctx == NULL) { |
91 | 0 | return SECFailure; |
92 | 0 | } |
93 | 0 | hashObj->begin(ctx); |
94 | 0 | hashObj->update(ctx, src, len); |
95 | 0 | hashObj->end(ctx, dest, &retLen, hashObj->length); |
96 | 0 | hashObj->destroy(ctx, PR_TRUE); |
97 | 0 | return SECSuccess; |
98 | 0 | } |
99 | | |
100 | | /* generate bits using any hash |
101 | | */ |
102 | | static SECItem * |
103 | | nsspkcs5_PBKDF1(const SECHashObject *hashObj, SECItem *salt, SECItem *pwd, |
104 | | int iter, PRBool faulty3DES) |
105 | 0 | { |
106 | 0 | SECItem *hash = NULL, *pre_hash = NULL; |
107 | 0 | SECStatus rv = SECFailure; |
108 | |
|
109 | 0 | if ((salt == NULL) || (pwd == NULL) || (iter < 0)) { |
110 | 0 | return NULL; |
111 | 0 | } |
112 | | |
113 | 0 | hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
114 | 0 | pre_hash = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
115 | |
|
116 | 0 | if ((hash != NULL) && (pre_hash != NULL)) { |
117 | 0 | int i, ph_len; |
118 | |
|
119 | 0 | ph_len = hashObj->length; |
120 | 0 | if ((salt->len + pwd->len) > hashObj->length) { |
121 | 0 | ph_len = salt->len + pwd->len; |
122 | 0 | } |
123 | |
|
124 | 0 | rv = SECFailure; |
125 | | |
126 | | /* allocate buffers */ |
127 | 0 | hash->len = hashObj->length; |
128 | 0 | hash->data = (unsigned char *)PORT_ZAlloc(hash->len); |
129 | 0 | pre_hash->data = (unsigned char *)PORT_ZAlloc(ph_len); |
130 | | |
131 | | /* in pbeSHA1TripleDESCBC there was an allocation error that made |
132 | | * it into the caller. We do not want to propagate those errors |
133 | | * further, so we are doing it correctly, but reading the old method. |
134 | | */ |
135 | 0 | if (faulty3DES) { |
136 | 0 | pre_hash->len = ph_len; |
137 | 0 | } else { |
138 | 0 | pre_hash->len = salt->len + pwd->len; |
139 | 0 | } |
140 | | |
141 | | /* preform hash */ |
142 | 0 | if ((hash->data != NULL) && (pre_hash->data != NULL)) { |
143 | 0 | rv = SECSuccess; |
144 | | /* check for 0 length password */ |
145 | 0 | if (pwd->len > 0) { |
146 | 0 | PORT_Memcpy(pre_hash->data, pwd->data, pwd->len); |
147 | 0 | } |
148 | 0 | if (salt->len > 0) { |
149 | 0 | PORT_Memcpy((pre_hash->data + pwd->len), salt->data, salt->len); |
150 | 0 | } |
151 | 0 | for (i = 0; ((i < iter) && (rv == SECSuccess)); i++) { |
152 | 0 | rv = nsspkcs5_HashBuf(hashObj, hash->data, |
153 | 0 | pre_hash->data, pre_hash->len); |
154 | 0 | if (rv != SECFailure) { |
155 | 0 | pre_hash->len = hashObj->length; |
156 | 0 | PORT_Memcpy(pre_hash->data, hash->data, hashObj->length); |
157 | 0 | } |
158 | 0 | } |
159 | 0 | } |
160 | 0 | } |
161 | |
|
162 | 0 | if (pre_hash != NULL) { |
163 | 0 | SECITEM_ZfreeItem(pre_hash, PR_TRUE); |
164 | 0 | } |
165 | |
|
166 | 0 | if ((rv != SECSuccess) && (hash != NULL)) { |
167 | 0 | SECITEM_ZfreeItem(hash, PR_TRUE); |
168 | 0 | hash = NULL; |
169 | 0 | } |
170 | |
|
171 | 0 | return hash; |
172 | 0 | } |
173 | | |
174 | | /* this bit generation routine is described in PKCS 12 and the proposed |
175 | | * extensions to PKCS 5. an initial hash is generated following the |
176 | | * instructions laid out in PKCS 5. If the number of bits generated is |
177 | | * insufficient, then the method discussed in the proposed extensions to |
178 | | * PKCS 5 in PKCS 12 are used. This extension makes use of the HMAC |
179 | | * function. And the P_Hash function from the TLS standard. |
180 | | */ |
181 | | static SECItem * |
182 | | nsspkcs5_PFXPBE(const SECHashObject *hashObj, NSSPKCS5PBEParameter *pbe_param, |
183 | | SECItem *init_hash, unsigned int bytes_needed) |
184 | 0 | { |
185 | 0 | SECItem *ret_bits = NULL; |
186 | 0 | int hash_size = 0; |
187 | 0 | unsigned int i; |
188 | 0 | unsigned int hash_iter; |
189 | 0 | unsigned int dig_len; |
190 | 0 | SECStatus rv = SECFailure; |
191 | 0 | unsigned char *state = NULL; |
192 | 0 | unsigned int state_len; |
193 | 0 | HMACContext *cx = NULL; |
194 | |
|
195 | 0 | hash_size = hashObj->length; |
196 | 0 | hash_iter = (bytes_needed + (unsigned int)hash_size - 1) / hash_size; |
197 | | |
198 | | /* allocate return buffer */ |
199 | 0 | ret_bits = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
200 | 0 | if (ret_bits == NULL) |
201 | 0 | return NULL; |
202 | 0 | ret_bits->data = (unsigned char *)PORT_ZAlloc((hash_iter * hash_size) + 1); |
203 | 0 | ret_bits->len = (hash_iter * hash_size); |
204 | 0 | if (ret_bits->data == NULL) { |
205 | 0 | PORT_Free(ret_bits); |
206 | 0 | return NULL; |
207 | 0 | } |
208 | | |
209 | | /* allocate intermediate hash buffer. 8 is for the 8 bytes of |
210 | | * data which are added based on iteration number |
211 | | */ |
212 | | |
213 | 0 | if ((unsigned int)hash_size > pbe_param->salt.len) { |
214 | 0 | state_len = hash_size; |
215 | 0 | } else { |
216 | 0 | state_len = pbe_param->salt.len; |
217 | 0 | } |
218 | 0 | state = (unsigned char *)PORT_ZAlloc(state_len); |
219 | 0 | if (state == NULL) { |
220 | 0 | rv = SECFailure; |
221 | 0 | goto loser; |
222 | 0 | } |
223 | 0 | if (pbe_param->salt.len > 0) { |
224 | 0 | PORT_Memcpy(state, pbe_param->salt.data, pbe_param->salt.len); |
225 | 0 | } |
226 | |
|
227 | 0 | cx = HMAC_Create(hashObj, init_hash->data, init_hash->len, PR_TRUE); |
228 | 0 | if (cx == NULL) { |
229 | 0 | rv = SECFailure; |
230 | 0 | goto loser; |
231 | 0 | } |
232 | | |
233 | 0 | for (i = 0; i < hash_iter; i++) { |
234 | | |
235 | | /* generate output bits */ |
236 | 0 | HMAC_Begin(cx); |
237 | 0 | HMAC_Update(cx, state, state_len); |
238 | 0 | HMAC_Update(cx, pbe_param->salt.data, pbe_param->salt.len); |
239 | 0 | rv = HMAC_Finish(cx, ret_bits->data + (i * hash_size), |
240 | 0 | &dig_len, hash_size); |
241 | 0 | if (rv != SECSuccess) |
242 | 0 | goto loser; |
243 | 0 | PORT_Assert((unsigned int)hash_size == dig_len); |
244 | | |
245 | | /* generate new state */ |
246 | 0 | HMAC_Begin(cx); |
247 | 0 | HMAC_Update(cx, state, state_len); |
248 | 0 | rv = HMAC_Finish(cx, state, &state_len, state_len); |
249 | 0 | if (rv != SECSuccess) |
250 | 0 | goto loser; |
251 | 0 | PORT_Assert(state_len == dig_len); |
252 | 0 | } |
253 | | |
254 | 0 | loser: |
255 | 0 | if (state != NULL) |
256 | 0 | PORT_ZFree(state, state_len); |
257 | 0 | HMAC_Destroy(cx, PR_TRUE); |
258 | |
|
259 | 0 | if (rv != SECSuccess) { |
260 | 0 | SECITEM_ZfreeItem(ret_bits, PR_TRUE); |
261 | 0 | ret_bits = NULL; |
262 | 0 | } |
263 | |
|
264 | 0 | return ret_bits; |
265 | 0 | } |
266 | | |
267 | | /* generate bits for the key and iv determination. if enough bits |
268 | | * are not generated using PKCS 5, then we need to generate more bits |
269 | | * based on the extension proposed in PKCS 12 |
270 | | */ |
271 | | static SECItem * |
272 | | nsspkcs5_PBKDF1Extended(const SECHashObject *hashObj, |
273 | | NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, PRBool faulty3DES) |
274 | 0 | { |
275 | 0 | SECItem *hash = NULL; |
276 | 0 | SECItem *newHash = NULL; |
277 | 0 | int bytes_needed; |
278 | 0 | int bytes_available; |
279 | |
|
280 | 0 | bytes_needed = pbe_param->ivLen + pbe_param->keyLen; |
281 | 0 | bytes_available = hashObj->length; |
282 | |
|
283 | 0 | hash = nsspkcs5_PBKDF1(hashObj, &pbe_param->salt, pwitem, |
284 | 0 | pbe_param->iter, faulty3DES); |
285 | |
|
286 | 0 | if (hash == NULL) { |
287 | 0 | return NULL; |
288 | 0 | } |
289 | | |
290 | 0 | if (bytes_needed <= bytes_available) { |
291 | 0 | return hash; |
292 | 0 | } |
293 | | |
294 | 0 | newHash = nsspkcs5_PFXPBE(hashObj, pbe_param, hash, bytes_needed); |
295 | 0 | if (hash != newHash) |
296 | 0 | SECITEM_ZfreeItem(hash, PR_TRUE); |
297 | 0 | return newHash; |
298 | 0 | } |
299 | | |
300 | | /* |
301 | | * PBDKDF2 is PKCS #5 v2.0 it's currently not used by NSS |
302 | | */ |
303 | | static void |
304 | | do_xor(unsigned char *dest, unsigned char *src, int len) |
305 | 0 | { |
306 | | /* use byt xor, not all platforms are happy about inaligned |
307 | | * integer fetches */ |
308 | 0 | while (len--) { |
309 | 0 | *dest = *dest ^ *src; |
310 | 0 | dest++; |
311 | 0 | src++; |
312 | 0 | } |
313 | 0 | } |
314 | | |
315 | | static SECStatus |
316 | | nsspkcs5_PBKDF2_F(const SECHashObject *hashobj, SECItem *pwitem, SECItem *salt, |
317 | | int iterations, unsigned int i, unsigned char *T) |
318 | 0 | { |
319 | 0 | int j; |
320 | 0 | HMACContext *cx = NULL; |
321 | 0 | unsigned int hLen = hashobj->length; |
322 | 0 | SECStatus rv = SECFailure; |
323 | 0 | unsigned char *last = NULL; |
324 | 0 | unsigned int lastLength = salt->len + 4; |
325 | 0 | unsigned int lastBufLength; |
326 | |
|
327 | 0 | cx = HMAC_Create(hashobj, pwitem->data, pwitem->len, PR_FALSE); |
328 | 0 | if (cx == NULL) { |
329 | 0 | goto loser; |
330 | 0 | } |
331 | 0 | PORT_Memset(T, 0, hLen); |
332 | 0 | lastBufLength = PR_MAX(lastLength, hLen); |
333 | 0 | last = PORT_Alloc(lastBufLength); |
334 | 0 | if (last == NULL) { |
335 | 0 | goto loser; |
336 | 0 | } |
337 | 0 | PORT_Memcpy(last, salt->data, salt->len); |
338 | 0 | last[salt->len] = (i >> 24) & 0xff; |
339 | 0 | last[salt->len + 1] = (i >> 16) & 0xff; |
340 | 0 | last[salt->len + 2] = (i >> 8) & 0xff; |
341 | 0 | last[salt->len + 3] = i & 0xff; |
342 | | |
343 | | /* NOTE: we need at least one iteration to return success! */ |
344 | 0 | for (j = 0; j < iterations; j++) { |
345 | 0 | HMAC_Begin(cx); |
346 | 0 | HMAC_Update(cx, last, lastLength); |
347 | 0 | rv = HMAC_Finish(cx, last, &lastLength, hLen); |
348 | 0 | if (rv != SECSuccess) { |
349 | 0 | break; |
350 | 0 | } |
351 | 0 | do_xor(T, last, hLen); |
352 | 0 | } |
353 | 0 | loser: |
354 | 0 | if (cx) { |
355 | 0 | HMAC_Destroy(cx, PR_TRUE); |
356 | 0 | } |
357 | 0 | if (last) { |
358 | 0 | PORT_ZFree(last, lastBufLength); |
359 | 0 | } |
360 | 0 | return rv; |
361 | 0 | } |
362 | | |
363 | | static SECItem * |
364 | | nsspkcs5_PBKDF2(const SECHashObject *hashobj, NSSPKCS5PBEParameter *pbe_param, |
365 | | SECItem *pwitem) |
366 | 0 | { |
367 | 0 | int iterations = pbe_param->iter; |
368 | 0 | int bytesNeeded = pbe_param->keyLen; |
369 | 0 | unsigned int dkLen = bytesNeeded; |
370 | 0 | unsigned int hLen = hashobj->length; |
371 | 0 | unsigned int nblocks = (dkLen + hLen - 1) / hLen; |
372 | 0 | unsigned int i; |
373 | 0 | unsigned char *rp; |
374 | 0 | unsigned char *T = NULL; |
375 | 0 | SECItem *result = NULL; |
376 | 0 | SECItem *salt = &pbe_param->salt; |
377 | 0 | SECStatus rv = SECFailure; |
378 | |
|
379 | 0 | result = SECITEM_AllocItem(NULL, NULL, nblocks * hLen); |
380 | 0 | if (result == NULL) { |
381 | 0 | return NULL; |
382 | 0 | } |
383 | | |
384 | 0 | T = PORT_Alloc(hLen); |
385 | 0 | if (T == NULL) { |
386 | 0 | goto loser; |
387 | 0 | } |
388 | | |
389 | 0 | for (i = 1, rp = result->data; i <= nblocks; i++, rp += hLen) { |
390 | 0 | rv = nsspkcs5_PBKDF2_F(hashobj, pwitem, salt, iterations, i, T); |
391 | 0 | if (rv != SECSuccess) { |
392 | 0 | break; |
393 | 0 | } |
394 | 0 | PORT_Memcpy(rp, T, hLen); |
395 | 0 | } |
396 | |
|
397 | 0 | loser: |
398 | 0 | if (T) { |
399 | 0 | PORT_ZFree(T, hLen); |
400 | 0 | } |
401 | 0 | if (rv != SECSuccess) { |
402 | 0 | SECITEM_ZfreeItem(result, PR_TRUE); |
403 | 0 | result = NULL; |
404 | 0 | } else { |
405 | 0 | result->len = dkLen; |
406 | 0 | } |
407 | |
|
408 | 0 | return result; |
409 | 0 | } |
410 | | |
411 | 0 | #define NSSPBE_ROUNDUP(x, y) ((((x) + ((y)-1)) / (y)) * (y)) |
412 | 0 | #define NSSPBE_MIN(x, y) ((x) < (y) ? (x) : (y)) |
413 | | /* |
414 | | * This is the extended PBE function defined by the final PKCS #12 spec. |
415 | | */ |
416 | | static SECItem * |
417 | | nsspkcs5_PKCS12PBE(const SECHashObject *hashObject, |
418 | | NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, |
419 | | PBEBitGenID bitGenPurpose, unsigned int bytesNeeded) |
420 | 0 | { |
421 | 0 | PLArenaPool *arena = NULL; |
422 | 0 | unsigned int SLen, PLen; |
423 | 0 | unsigned int hashLength = hashObject->length; |
424 | 0 | unsigned char *S, *P; |
425 | 0 | SECItem *A = NULL, B, D, I; |
426 | 0 | SECItem *salt = &pbe_param->salt; |
427 | 0 | unsigned int c, i = 0; |
428 | 0 | unsigned int hashLen; |
429 | 0 | int iter; |
430 | 0 | unsigned char *iterBuf; |
431 | 0 | void *hash = NULL; |
432 | 0 | unsigned int bufferLength; |
433 | |
|
434 | 0 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
435 | 0 | if (!arena) { |
436 | 0 | return NULL; |
437 | 0 | } |
438 | | |
439 | | /* how many hash object lengths are needed */ |
440 | 0 | c = (bytesNeeded + (hashLength - 1)) / hashLength; |
441 | | |
442 | | /* 64 if 0 < hashLength <= 32, 128 if 32 < hashLength <= 64 */ |
443 | 0 | bufferLength = NSSPBE_ROUNDUP(hashLength * 2, 64); |
444 | | |
445 | | /* initialize our buffers */ |
446 | 0 | D.len = bufferLength; |
447 | | /* B and D are the same length, use one alloc go get both */ |
448 | 0 | D.data = (unsigned char *)PORT_ArenaZAlloc(arena, D.len * 2); |
449 | 0 | B.len = D.len; |
450 | 0 | B.data = D.data + D.len; |
451 | | |
452 | | /* if all goes well, A will be returned, so don't use our temp arena */ |
453 | 0 | A = SECITEM_AllocItem(NULL, NULL, c * hashLength); |
454 | 0 | if (A == NULL) { |
455 | 0 | goto loser; |
456 | 0 | } |
457 | | |
458 | 0 | SLen = NSSPBE_ROUNDUP(salt->len, bufferLength); |
459 | 0 | PLen = NSSPBE_ROUNDUP(pwitem->len, bufferLength); |
460 | 0 | I.len = SLen + PLen; |
461 | 0 | I.data = (unsigned char *)PORT_ArenaZAlloc(arena, I.len); |
462 | 0 | if (I.data == NULL) { |
463 | 0 | goto loser; |
464 | 0 | } |
465 | | |
466 | | /* S & P are only used to initialize I */ |
467 | 0 | S = I.data; |
468 | 0 | P = S + SLen; |
469 | |
|
470 | 0 | PORT_Memset(D.data, (char)bitGenPurpose, D.len); |
471 | 0 | if (SLen) { |
472 | 0 | for (i = 0; i < SLen; i += salt->len) { |
473 | 0 | PORT_Memcpy(S + i, salt->data, NSSPBE_MIN(SLen - i, salt->len)); |
474 | 0 | } |
475 | 0 | } |
476 | 0 | if (PLen) { |
477 | 0 | for (i = 0; i < PLen; i += pwitem->len) { |
478 | 0 | PORT_Memcpy(P + i, pwitem->data, NSSPBE_MIN(PLen - i, pwitem->len)); |
479 | 0 | } |
480 | 0 | } |
481 | |
|
482 | 0 | iterBuf = (unsigned char *)PORT_ArenaZAlloc(arena, hashLength); |
483 | 0 | if (iterBuf == NULL) { |
484 | 0 | goto loser; |
485 | 0 | } |
486 | | |
487 | 0 | hash = hashObject->create(); |
488 | 0 | if (!hash) { |
489 | 0 | goto loser; |
490 | 0 | } |
491 | | /* calculate the PBE now */ |
492 | 0 | for (i = 0; i < c; i++) { |
493 | 0 | int Bidx; /* must be signed or the for loop won't terminate */ |
494 | 0 | unsigned int k, j; |
495 | 0 | unsigned char *Ai = A->data + i * hashLength; |
496 | |
|
497 | 0 | for (iter = 0; iter < pbe_param->iter; iter++) { |
498 | 0 | hashObject->begin(hash); |
499 | |
|
500 | 0 | if (iter) { |
501 | 0 | hashObject->update(hash, iterBuf, hashLen); |
502 | 0 | } else { |
503 | 0 | hashObject->update(hash, D.data, D.len); |
504 | 0 | hashObject->update(hash, I.data, I.len); |
505 | 0 | } |
506 | |
|
507 | 0 | hashObject->end(hash, iterBuf, &hashLen, hashObject->length); |
508 | 0 | if (hashLen != hashObject->length) { |
509 | 0 | break; |
510 | 0 | } |
511 | 0 | } |
512 | |
|
513 | 0 | PORT_Memcpy(Ai, iterBuf, hashLength); |
514 | 0 | for (Bidx = 0; Bidx < (int)B.len; Bidx += hashLength) { |
515 | 0 | PORT_Memcpy(B.data + Bidx, iterBuf, NSSPBE_MIN(B.len - Bidx, hashLength)); |
516 | 0 | } |
517 | |
|
518 | 0 | k = I.len / B.len; |
519 | 0 | for (j = 0; j < k; j++) { |
520 | 0 | unsigned int q, carryBit; |
521 | 0 | unsigned char *Ij = I.data + j * B.len; |
522 | | |
523 | | /* (Ij = Ij+B+1) */ |
524 | 0 | for (Bidx = (B.len - 1), q = 1, carryBit = 0; Bidx >= 0; Bidx--, q = 0) { |
525 | 0 | q += (unsigned int)Ij[Bidx]; |
526 | 0 | q += (unsigned int)B.data[Bidx]; |
527 | 0 | q += carryBit; |
528 | |
|
529 | 0 | carryBit = (q > 0xff); |
530 | 0 | Ij[Bidx] = (unsigned char)(q & 0xff); |
531 | 0 | } |
532 | 0 | } |
533 | 0 | } |
534 | 0 | loser: |
535 | 0 | if (hash) { |
536 | 0 | hashObject->destroy(hash, PR_TRUE); |
537 | 0 | } |
538 | 0 | if (arena) { |
539 | 0 | PORT_FreeArena(arena, PR_TRUE); |
540 | 0 | } |
541 | |
|
542 | 0 | if (A) { |
543 | | /* if i != c, then we didn't complete the loop above and must of failed |
544 | | * somwhere along the way */ |
545 | 0 | if (i != c) { |
546 | 0 | SECITEM_ZfreeItem(A, PR_TRUE); |
547 | 0 | A = NULL; |
548 | 0 | } else { |
549 | 0 | A->len = bytesNeeded; |
550 | 0 | } |
551 | 0 | } |
552 | |
|
553 | 0 | return A; |
554 | 0 | } |
555 | | |
556 | | struct KDFCacheItemStr { |
557 | | SECItem *hash; |
558 | | SECItem *salt; |
559 | | SECItem *pwItem; |
560 | | HASH_HashType hashType; |
561 | | int iterations; |
562 | | int keyLen; |
563 | | }; |
564 | | typedef struct KDFCacheItemStr KDFCacheItem; |
565 | | |
566 | | /* Bug 1606992 - Cache the hash result for the common case that we're |
567 | | * asked to repeatedly compute the key for the same password item, |
568 | | * hash, iterations and salt. */ |
569 | 1.66k | #define KDF2_CACHE_COUNT 150 |
570 | | static struct { |
571 | | PZLock *lock; |
572 | | struct { |
573 | | KDFCacheItem common; |
574 | | int ivLen; |
575 | | PRBool faulty3DES; |
576 | | } cacheKDF1; |
577 | | struct { |
578 | | KDFCacheItem common[KDF2_CACHE_COUNT]; |
579 | | int next; |
580 | | } cacheKDF2; |
581 | | } PBECache; |
582 | | |
583 | | void |
584 | | sftk_PBELockInit(void) |
585 | 11 | { |
586 | 11 | if (!PBECache.lock) { |
587 | 11 | PBECache.lock = PZ_NewLock(nssIPBECacheLock); |
588 | 11 | } |
589 | 11 | } |
590 | | |
591 | | static void |
592 | | sftk_clearPBECommonCacheItemsLocked(KDFCacheItem *item) |
593 | 1.66k | { |
594 | 1.66k | if (item->hash) { |
595 | 0 | SECITEM_ZfreeItem(item->hash, PR_TRUE); |
596 | 0 | item->hash = NULL; |
597 | 0 | } |
598 | 1.66k | if (item->salt) { |
599 | 0 | SECITEM_ZfreeItem(item->salt, PR_TRUE); |
600 | 0 | item->salt = NULL; |
601 | 0 | } |
602 | 1.66k | if (item->pwItem) { |
603 | 0 | SECITEM_ZfreeItem(item->pwItem, PR_TRUE); |
604 | 0 | item->pwItem = NULL; |
605 | 0 | } |
606 | 1.66k | } |
607 | | |
608 | | static void |
609 | | sftk_setPBECommonCacheItemsKDFLocked(KDFCacheItem *cacheItem, |
610 | | const SECItem *hash, |
611 | | const NSSPKCS5PBEParameter *pbe_param, |
612 | | const SECItem *pwItem) |
613 | 0 | { |
614 | 0 | cacheItem->hash = SECITEM_DupItem(hash); |
615 | 0 | cacheItem->hashType = pbe_param->hashType; |
616 | 0 | cacheItem->iterations = pbe_param->iter; |
617 | 0 | cacheItem->keyLen = pbe_param->keyLen; |
618 | 0 | cacheItem->salt = SECITEM_DupItem(&pbe_param->salt); |
619 | 0 | cacheItem->pwItem = SECITEM_DupItem(pwItem); |
620 | 0 | } |
621 | | |
622 | | static void |
623 | | sftk_setPBECacheKDF2(const SECItem *hash, |
624 | | const NSSPKCS5PBEParameter *pbe_param, |
625 | | const SECItem *pwItem) |
626 | 0 | { |
627 | 0 | PZ_Lock(PBECache.lock); |
628 | 0 | KDFCacheItem *next = &PBECache.cacheKDF2.common[PBECache.cacheKDF2.next]; |
629 | |
|
630 | 0 | sftk_clearPBECommonCacheItemsLocked(next); |
631 | |
|
632 | 0 | sftk_setPBECommonCacheItemsKDFLocked(next, hash, pbe_param, pwItem); |
633 | 0 | PBECache.cacheKDF2.next++; |
634 | 0 | if (PBECache.cacheKDF2.next >= KDF2_CACHE_COUNT) { |
635 | 0 | PBECache.cacheKDF2.next = 0; |
636 | 0 | } |
637 | |
|
638 | 0 | PZ_Unlock(PBECache.lock); |
639 | 0 | } |
640 | | |
641 | | static void |
642 | | sftk_setPBECacheKDF1(const SECItem *hash, |
643 | | const NSSPKCS5PBEParameter *pbe_param, |
644 | | const SECItem *pwItem, |
645 | | PRBool faulty3DES) |
646 | 0 | { |
647 | 0 | PZ_Lock(PBECache.lock); |
648 | |
|
649 | 0 | sftk_clearPBECommonCacheItemsLocked(&PBECache.cacheKDF1.common); |
650 | |
|
651 | 0 | sftk_setPBECommonCacheItemsKDFLocked(&PBECache.cacheKDF1.common, |
652 | 0 | hash, pbe_param, pwItem); |
653 | 0 | PBECache.cacheKDF1.faulty3DES = faulty3DES; |
654 | 0 | PBECache.cacheKDF1.ivLen = pbe_param->ivLen; |
655 | |
|
656 | 0 | PZ_Unlock(PBECache.lock); |
657 | 0 | } |
658 | | |
659 | | static PRBool |
660 | | sftk_comparePBECommonCacheItemLocked(const KDFCacheItem *cacheItem, |
661 | | const NSSPKCS5PBEParameter *pbe_param, |
662 | | const SECItem *pwItem) |
663 | 0 | { |
664 | 0 | return (cacheItem->hash && |
665 | 0 | cacheItem->salt && |
666 | 0 | cacheItem->pwItem && |
667 | 0 | pbe_param->hashType == cacheItem->hashType && |
668 | 0 | pbe_param->iter == cacheItem->iterations && |
669 | 0 | pbe_param->keyLen == cacheItem->keyLen && |
670 | 0 | SECITEM_ItemsAreEqual(&pbe_param->salt, cacheItem->salt) && |
671 | 0 | SECITEM_ItemsAreEqual(pwItem, cacheItem->pwItem)); |
672 | 0 | } |
673 | | |
674 | | static SECItem * |
675 | | sftk_getPBECacheKDF2(const NSSPKCS5PBEParameter *pbe_param, |
676 | | const SECItem *pwItem) |
677 | 0 | { |
678 | 0 | SECItem *result = NULL; |
679 | 0 | int i; |
680 | |
|
681 | 0 | PZ_Lock(PBECache.lock); |
682 | 0 | for (i = 0; i < KDF2_CACHE_COUNT; i++) { |
683 | 0 | const KDFCacheItem *cacheItem = &PBECache.cacheKDF2.common[i]; |
684 | 0 | if (sftk_comparePBECommonCacheItemLocked(cacheItem, |
685 | 0 | pbe_param, pwItem)) { |
686 | 0 | result = SECITEM_DupItem(cacheItem->hash); |
687 | 0 | break; |
688 | 0 | } |
689 | 0 | } |
690 | 0 | PZ_Unlock(PBECache.lock); |
691 | |
|
692 | 0 | return result; |
693 | 0 | } |
694 | | |
695 | | static SECItem * |
696 | | sftk_getPBECacheKDF1(const NSSPKCS5PBEParameter *pbe_param, |
697 | | const SECItem *pwItem, |
698 | | PRBool faulty3DES) |
699 | 0 | { |
700 | 0 | SECItem *result = NULL; |
701 | 0 | const KDFCacheItem *cacheItem = &PBECache.cacheKDF1.common; |
702 | |
|
703 | 0 | PZ_Lock(PBECache.lock); |
704 | 0 | if (sftk_comparePBECommonCacheItemLocked(cacheItem, pbe_param, pwItem) && |
705 | 0 | PBECache.cacheKDF1.faulty3DES == faulty3DES && |
706 | 0 | PBECache.cacheKDF1.ivLen == pbe_param->ivLen) { |
707 | 0 | result = SECITEM_DupItem(cacheItem->hash); |
708 | 0 | } |
709 | 0 | PZ_Unlock(PBECache.lock); |
710 | |
|
711 | 0 | return result; |
712 | 0 | } |
713 | | |
714 | | void |
715 | | sftk_PBELockShutdown(void) |
716 | 11 | { |
717 | 11 | int i; |
718 | 11 | if (PBECache.lock) { |
719 | 11 | PZ_DestroyLock(PBECache.lock); |
720 | 11 | PBECache.lock = 0; |
721 | 11 | } |
722 | 11 | sftk_clearPBECommonCacheItemsLocked(&PBECache.cacheKDF1.common); |
723 | 1.66k | for (i = 0; i < KDF2_CACHE_COUNT; i++) { |
724 | 1.65k | sftk_clearPBECommonCacheItemsLocked(&PBECache.cacheKDF2.common[i]); |
725 | 1.65k | } |
726 | 11 | PBECache.cacheKDF2.next = 0; |
727 | 11 | } |
728 | | |
729 | | /* |
730 | | * generate key as per PKCS 5 |
731 | | */ |
732 | | SECItem * |
733 | | nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, |
734 | | SECItem *iv, PRBool faulty3DES) |
735 | 0 | { |
736 | 0 | SECItem *hash = NULL, *key = NULL; |
737 | 0 | const SECHashObject *hashObj; |
738 | 0 | PRBool getIV = PR_FALSE; |
739 | |
|
740 | 0 | if ((pbe_param == NULL) || (pwitem == NULL)) { |
741 | 0 | return NULL; |
742 | 0 | } |
743 | | |
744 | 0 | key = SECITEM_AllocItem(NULL, NULL, pbe_param->keyLen); |
745 | 0 | if (key == NULL) { |
746 | 0 | return NULL; |
747 | 0 | } |
748 | | |
749 | 0 | if (iv && (pbe_param->ivLen) && (iv->data == NULL)) { |
750 | 0 | getIV = PR_TRUE; |
751 | 0 | iv->data = (unsigned char *)PORT_Alloc(pbe_param->ivLen); |
752 | 0 | if (iv->data == NULL) { |
753 | 0 | goto loser; |
754 | 0 | } |
755 | 0 | iv->len = pbe_param->ivLen; |
756 | 0 | } |
757 | | |
758 | 0 | hashObj = HASH_GetRawHashObject(pbe_param->hashType); |
759 | 0 | switch (pbe_param->pbeType) { |
760 | 0 | case NSSPKCS5_PBKDF1: |
761 | 0 | hash = sftk_getPBECacheKDF1(pbe_param, pwitem, faulty3DES); |
762 | 0 | if (!hash) { |
763 | 0 | hash = nsspkcs5_PBKDF1Extended(hashObj, pbe_param, pwitem, faulty3DES); |
764 | 0 | sftk_setPBECacheKDF1(hash, pbe_param, pwitem, faulty3DES); |
765 | 0 | } |
766 | 0 | if (hash == NULL) { |
767 | 0 | goto loser; |
768 | 0 | } |
769 | 0 | PORT_Assert(hash->len >= key->len + (getIV ? iv->len : 0)); |
770 | 0 | if (getIV) { |
771 | 0 | PORT_Memcpy(iv->data, hash->data + (hash->len - iv->len), iv->len); |
772 | 0 | } |
773 | |
|
774 | 0 | break; |
775 | 0 | case NSSPKCS5_PBKDF2: |
776 | 0 | hash = sftk_getPBECacheKDF2(pbe_param, pwitem); |
777 | 0 | if (!hash) { |
778 | 0 | hash = nsspkcs5_PBKDF2(hashObj, pbe_param, pwitem); |
779 | 0 | sftk_setPBECacheKDF2(hash, pbe_param, pwitem); |
780 | 0 | } |
781 | 0 | if (getIV) { |
782 | 0 | PORT_Memcpy(iv->data, pbe_param->ivData, iv->len); |
783 | 0 | } |
784 | 0 | break; |
785 | 0 | case NSSPKCS5_PKCS12_V2: |
786 | 0 | if (getIV) { |
787 | 0 | hash = nsspkcs5_PKCS12PBE(hashObj, pbe_param, pwitem, |
788 | 0 | pbeBitGenCipherIV, iv->len); |
789 | 0 | if (hash == NULL) { |
790 | 0 | goto loser; |
791 | 0 | } |
792 | 0 | PORT_Memcpy(iv->data, hash->data, iv->len); |
793 | 0 | SECITEM_ZfreeItem(hash, PR_TRUE); |
794 | 0 | hash = NULL; |
795 | 0 | } |
796 | 0 | hash = nsspkcs5_PKCS12PBE(hashObj, pbe_param, pwitem, |
797 | 0 | pbe_param->keyID, key->len); |
798 | 0 | default: |
799 | 0 | break; |
800 | 0 | } |
801 | | |
802 | 0 | if (hash == NULL) { |
803 | 0 | goto loser; |
804 | 0 | } |
805 | | |
806 | 0 | PORT_Memcpy(key->data, hash->data, key->len); |
807 | |
|
808 | 0 | SECITEM_ZfreeItem(hash, PR_TRUE); |
809 | 0 | return key; |
810 | | |
811 | 0 | loser: |
812 | 0 | if (getIV && iv->data) { |
813 | 0 | PORT_ZFree(iv->data, iv->len); |
814 | 0 | iv->data = NULL; |
815 | 0 | } |
816 | |
|
817 | 0 | SECITEM_ZfreeItem(key, PR_TRUE); |
818 | 0 | return NULL; |
819 | 0 | } |
820 | | |
821 | | #define MAX_IV_LENGTH 64 |
822 | | /* get a random IV into the parameters */ |
823 | | static SECStatus |
824 | | nsspkcs5_SetIVParam(NSSPKCS5PBEParameter *pbe_param, int ivLen) |
825 | 0 | { |
826 | 0 | SECStatus rv; |
827 | 0 | SECItem derIV; |
828 | 0 | SECItem iv; |
829 | 0 | SECItem *dummy = NULL; |
830 | 0 | unsigned char ivData[MAX_IV_LENGTH]; |
831 | |
|
832 | 0 | PORT_Assert(ivLen <= MAX_IV_LENGTH); |
833 | | |
834 | | /* Because of a bug in the decode section, the IV's not are expected |
835 | | * to be der encoded, but still need to parse as if they were der data. |
836 | | * because we want to be compatible with existing versions of nss that |
837 | | * have that bug, create an IV that looks like der data. That still |
838 | | * leaves 14 bytes of entropy in the IV */ |
839 | 0 | rv = RNG_GenerateGlobalRandomBytes(ivData, ivLen - 2); |
840 | 0 | if (rv != SECSuccess) { |
841 | 0 | return SECFailure; |
842 | 0 | } |
843 | 0 | derIV.data = NULL; |
844 | 0 | derIV.len = 0; |
845 | 0 | iv.data = ivData; |
846 | 0 | iv.len = ivLen - 2; |
847 | 0 | dummy = SEC_ASN1EncodeItem(pbe_param->poolp, &derIV, &iv, |
848 | 0 | SEC_ASN1_GET(SEC_OctetStringTemplate)); |
849 | 0 | if (dummy == NULL) { |
850 | 0 | return SECFailure; |
851 | 0 | } |
852 | 0 | pbe_param->ivData = derIV.data; |
853 | 0 | pbe_param->ivLen = derIV.len; |
854 | 0 | PORT_Assert(pbe_param->ivLen == ivLen); |
855 | 0 | return SECSuccess; |
856 | 0 | } |
857 | | |
858 | | static SECStatus |
859 | | nsspkcs5_FillInParam(SECOidTag algorithm, HASH_HashType hashType, |
860 | | NSSPKCS5PBEParameter *pbe_param) |
861 | 0 | { |
862 | 0 | PRBool skipType = PR_FALSE; |
863 | 0 | SECStatus rv; |
864 | |
|
865 | 0 | pbe_param->keyLen = 5; |
866 | 0 | pbe_param->ivLen = 8; |
867 | 0 | pbe_param->hashType = hashType; |
868 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF1; |
869 | 0 | pbe_param->encAlg = SEC_OID_RC2_CBC; |
870 | 0 | pbe_param->is2KeyDES = PR_FALSE; |
871 | 0 | switch (algorithm) { |
872 | | /* DES3 Algorithms */ |
873 | 0 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: |
874 | 0 | pbe_param->is2KeyDES = PR_TRUE; |
875 | 0 | pbe_param->pbeType = NSSPKCS5_PKCS12_V2; |
876 | 0 | pbe_param->keyLen = 16; |
877 | 0 | pbe_param->encAlg = SEC_OID_DES_EDE3_CBC; |
878 | 0 | break; |
879 | 0 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: |
880 | 0 | pbe_param->pbeType = NSSPKCS5_PKCS12_V2; |
881 | 0 | pbe_param->keyLen = 24; |
882 | 0 | pbe_param->encAlg = SEC_OID_DES_EDE3_CBC; |
883 | 0 | break; |
884 | 0 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: |
885 | 0 | pbe_param->keyLen = 24; |
886 | 0 | pbe_param->encAlg = SEC_OID_DES_EDE3_CBC; |
887 | 0 | break; |
888 | | |
889 | | /* DES Algorithms */ |
890 | 0 | case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC: |
891 | 0 | pbe_param->hashType = HASH_AlgMD2; |
892 | 0 | goto finish_des; |
893 | 0 | case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: |
894 | 0 | pbe_param->hashType = HASH_AlgMD5; |
895 | | /* fall through */ |
896 | 0 | case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: |
897 | 0 | finish_des: |
898 | 0 | pbe_param->keyLen = 8; |
899 | 0 | pbe_param->encAlg = SEC_OID_DES_CBC; |
900 | 0 | break; |
901 | | |
902 | 0 | #ifndef NSS_DISABLE_DEPRECATED_RC2 |
903 | | /* RC2 Algorithms */ |
904 | 0 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
905 | 0 | pbe_param->keyLen = 16; |
906 | | /* fall through */ |
907 | 0 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
908 | 0 | pbe_param->pbeType = NSSPKCS5_PKCS12_V2; |
909 | 0 | break; |
910 | 0 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
911 | 0 | pbe_param->keyLen = 16; |
912 | | /* fall through */ |
913 | 0 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
914 | 0 | break; |
915 | 0 | #endif |
916 | | |
917 | | /* RC4 algorithms */ |
918 | 0 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: |
919 | 0 | skipType = PR_TRUE; |
920 | | /* fall through */ |
921 | 0 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: |
922 | 0 | pbe_param->keyLen = 16; |
923 | | /* fall through */ |
924 | 0 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: |
925 | 0 | if (!skipType) { |
926 | 0 | pbe_param->pbeType = NSSPKCS5_PKCS12_V2; |
927 | 0 | } |
928 | | /* fall through */ |
929 | 0 | case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: |
930 | 0 | pbe_param->ivLen = 0; |
931 | 0 | pbe_param->encAlg = SEC_OID_RC4; |
932 | 0 | break; |
933 | | |
934 | 0 | case SEC_OID_PKCS5_PBKDF2: |
935 | 0 | case SEC_OID_PKCS5_PBES2: |
936 | 0 | case SEC_OID_PKCS5_PBMAC1: |
937 | | /* everything else will be filled in by the template */ |
938 | 0 | pbe_param->ivLen = 0; |
939 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
940 | 0 | pbe_param->encAlg = SEC_OID_PKCS5_PBKDF2; |
941 | 0 | pbe_param->keyLen = 0; /* needs to be set by caller after return */ |
942 | 0 | break; |
943 | | /* AES uses PBKDF2 */ |
944 | 0 | case SEC_OID_AES_128_CBC: |
945 | 0 | rv = nsspkcs5_SetIVParam(pbe_param, 16); |
946 | 0 | if (rv != SECSuccess) { |
947 | 0 | return rv; |
948 | 0 | } |
949 | 0 | pbe_param->ivLen = 16; |
950 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
951 | 0 | pbe_param->encAlg = algorithm; |
952 | 0 | pbe_param->keyLen = 128 / 8; |
953 | 0 | break; |
954 | 0 | case SEC_OID_AES_192_CBC: |
955 | 0 | rv = nsspkcs5_SetIVParam(pbe_param, 16); |
956 | 0 | if (rv != SECSuccess) { |
957 | 0 | return rv; |
958 | 0 | } |
959 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
960 | 0 | pbe_param->encAlg = algorithm; |
961 | 0 | pbe_param->keyLen = 192 / 8; |
962 | 0 | break; |
963 | 0 | case SEC_OID_AES_256_CBC: |
964 | 0 | rv = nsspkcs5_SetIVParam(pbe_param, 16); |
965 | 0 | if (rv != SECSuccess) { |
966 | 0 | return rv; |
967 | 0 | } |
968 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
969 | 0 | pbe_param->encAlg = algorithm; |
970 | 0 | pbe_param->keyLen = 256 / 8; |
971 | 0 | break; |
972 | 0 | case SEC_OID_AES_128_KEY_WRAP: |
973 | 0 | pbe_param->ivLen = 0; |
974 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
975 | 0 | pbe_param->encAlg = algorithm; |
976 | 0 | pbe_param->keyLen = 128 / 8; |
977 | 0 | break; |
978 | 0 | case SEC_OID_AES_192_KEY_WRAP: |
979 | 0 | pbe_param->ivLen = 0; |
980 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
981 | 0 | pbe_param->encAlg = algorithm; |
982 | 0 | pbe_param->keyLen = 192 / 8; |
983 | 0 | break; |
984 | 0 | case SEC_OID_AES_256_KEY_WRAP: |
985 | 0 | pbe_param->ivLen = 0; |
986 | 0 | pbe_param->pbeType = NSSPKCS5_PBKDF2; |
987 | 0 | pbe_param->encAlg = algorithm; |
988 | 0 | pbe_param->keyLen = 256 / 8; |
989 | 0 | break; |
990 | | |
991 | 0 | default: |
992 | 0 | return SECFailure; |
993 | 0 | } |
994 | 0 | if (pbe_param->pbeType == NSSPKCS5_PBKDF2) { |
995 | 0 | SECOidTag prfAlg = HASH_HMACOidFromHash(pbe_param->hashType); |
996 | 0 | if (prfAlg == SEC_OID_UNKNOWN) { |
997 | 0 | return SECFailure; |
998 | 0 | } |
999 | 0 | rv = SECOID_SetAlgorithmID(pbe_param->poolp, &pbe_param->prfAlg, |
1000 | 0 | prfAlg, NULL); |
1001 | 0 | if (rv != SECSuccess) { |
1002 | 0 | return rv; |
1003 | 0 | } |
1004 | 0 | } |
1005 | 0 | return SECSuccess; |
1006 | 0 | } |
1007 | | |
1008 | | /* decode the algid and generate a PKCS 5 parameter from it |
1009 | | */ |
1010 | | NSSPKCS5PBEParameter * |
1011 | | nsspkcs5_NewParam(SECOidTag alg, HASH_HashType hashType, SECItem *salt, |
1012 | | int iterationCount) |
1013 | 0 | { |
1014 | 0 | PLArenaPool *arena = NULL; |
1015 | 0 | NSSPKCS5PBEParameter *pbe_param = NULL; |
1016 | 0 | SECStatus rv = SECFailure; |
1017 | |
|
1018 | 0 | arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
1019 | 0 | if (arena == NULL) |
1020 | 0 | return NULL; |
1021 | | |
1022 | | /* allocate memory for the parameter */ |
1023 | 0 | pbe_param = (NSSPKCS5PBEParameter *)PORT_ArenaZAlloc(arena, |
1024 | 0 | sizeof(NSSPKCS5PBEParameter)); |
1025 | |
|
1026 | 0 | if (pbe_param == NULL) { |
1027 | 0 | goto loser; |
1028 | 0 | } |
1029 | | |
1030 | 0 | pbe_param->poolp = arena; |
1031 | |
|
1032 | 0 | rv = nsspkcs5_FillInParam(alg, hashType, pbe_param); |
1033 | 0 | if (rv != SECSuccess) { |
1034 | 0 | goto loser; |
1035 | 0 | } |
1036 | | |
1037 | 0 | pbe_param->iter = iterationCount; |
1038 | 0 | if (salt) { |
1039 | 0 | rv = SECITEM_CopyItem(arena, &pbe_param->salt, salt); |
1040 | 0 | } |
1041 | | |
1042 | | /* default key gen */ |
1043 | 0 | pbe_param->keyID = pbeBitGenCipherKey; |
1044 | |
|
1045 | 0 | loser: |
1046 | 0 | if (rv != SECSuccess) { |
1047 | 0 | PORT_FreeArena(arena, PR_TRUE); |
1048 | 0 | pbe_param = NULL; |
1049 | 0 | } |
1050 | |
|
1051 | 0 | return pbe_param; |
1052 | 0 | } |
1053 | | |
1054 | | /* |
1055 | | * find the hash type needed to implement a specific HMAC. |
1056 | | * OID definitions are from pkcs 5 v2.0 and 2.1 |
1057 | | */ |
1058 | | HASH_HashType |
1059 | | HASH_FromHMACOid(SECOidTag hmac) |
1060 | 0 | { |
1061 | 0 | switch (hmac) { |
1062 | 0 | case SEC_OID_HMAC_SHA1: |
1063 | 0 | return HASH_AlgSHA1; |
1064 | 0 | case SEC_OID_HMAC_SHA256: |
1065 | 0 | return HASH_AlgSHA256; |
1066 | 0 | case SEC_OID_HMAC_SHA384: |
1067 | 0 | return HASH_AlgSHA384; |
1068 | 0 | case SEC_OID_HMAC_SHA512: |
1069 | 0 | return HASH_AlgSHA512; |
1070 | 0 | case SEC_OID_HMAC_SHA224: |
1071 | 0 | default: |
1072 | 0 | break; |
1073 | 0 | } |
1074 | 0 | return HASH_AlgNULL; |
1075 | 0 | } |
1076 | | |
1077 | | SECOidTag |
1078 | | HASH_HMACOidFromHash(HASH_HashType hashType) |
1079 | 0 | { |
1080 | 0 | switch (hashType) { |
1081 | 0 | case HASH_AlgSHA1: |
1082 | 0 | return SEC_OID_HMAC_SHA1; |
1083 | 0 | case HASH_AlgSHA256: |
1084 | 0 | return SEC_OID_HMAC_SHA256; |
1085 | 0 | case HASH_AlgSHA384: |
1086 | 0 | return SEC_OID_HMAC_SHA384; |
1087 | 0 | case HASH_AlgSHA512: |
1088 | 0 | return SEC_OID_HMAC_SHA512; |
1089 | 0 | case HASH_AlgSHA224: |
1090 | 0 | return SEC_OID_HMAC_SHA224; |
1091 | 0 | case HASH_AlgMD2: |
1092 | 0 | case HASH_AlgMD5: |
1093 | 0 | case HASH_AlgTOTAL: |
1094 | 0 | default: |
1095 | 0 | break; |
1096 | 0 | } |
1097 | 0 | return SEC_OID_UNKNOWN; |
1098 | 0 | } |
1099 | | |
1100 | | /* decode the algid and generate a PKCS 5 parameter from it |
1101 | | */ |
1102 | | NSSPKCS5PBEParameter * |
1103 | | nsspkcs5_AlgidToParam(SECAlgorithmID *algid) |
1104 | 0 | { |
1105 | 0 | NSSPKCS5PBEParameter *pbe_param = NULL; |
1106 | 0 | nsspkcs5V2PBEParameter pbev2_param; |
1107 | 0 | SECOidTag algorithm; |
1108 | 0 | SECStatus rv = SECFailure; |
1109 | |
|
1110 | 0 | if (algid == NULL) { |
1111 | 0 | return NULL; |
1112 | 0 | } |
1113 | | |
1114 | 0 | algorithm = SECOID_GetAlgorithmTag(algid); |
1115 | 0 | if (algorithm == SEC_OID_UNKNOWN) { |
1116 | 0 | goto loser; |
1117 | 0 | } |
1118 | | |
1119 | 0 | pbe_param = nsspkcs5_NewParam(algorithm, HASH_AlgSHA1, NULL, 1); |
1120 | 0 | if (pbe_param == NULL) { |
1121 | 0 | goto loser; |
1122 | 0 | } |
1123 | | |
1124 | | /* decode parameter */ |
1125 | 0 | rv = SECFailure; |
1126 | 0 | switch (pbe_param->pbeType) { |
1127 | 0 | case NSSPKCS5_PBKDF1: |
1128 | 0 | rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, |
1129 | 0 | NSSPKCS5PBEParameterTemplate, &algid->parameters); |
1130 | 0 | break; |
1131 | 0 | case NSSPKCS5_PKCS12_V2: |
1132 | 0 | rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, |
1133 | 0 | NSSPKCS5PKCS12V2PBEParameterTemplate, &algid->parameters); |
1134 | 0 | break; |
1135 | 0 | case NSSPKCS5_PBKDF2: |
1136 | 0 | PORT_Memset(&pbev2_param, 0, sizeof(pbev2_param)); |
1137 | | /* just the PBE */ |
1138 | 0 | if (algorithm == SEC_OID_PKCS5_PBKDF2) { |
1139 | 0 | rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, |
1140 | 0 | NSSPKCS5V2PBEParameterTemplate, &algid->parameters); |
1141 | 0 | } else { |
1142 | | /* PBE data an others */ |
1143 | 0 | rv = SEC_ASN1DecodeItem(pbe_param->poolp, &pbev2_param, |
1144 | 0 | NSSPKCS5V2PBES2ParameterTemplate, &algid->parameters); |
1145 | 0 | if (rv != SECSuccess) { |
1146 | 0 | break; |
1147 | 0 | } |
1148 | 0 | pbe_param->encAlg = SECOID_GetAlgorithmTag(&pbev2_param.algParams); |
1149 | 0 | rv = SEC_ASN1DecodeItem(pbe_param->poolp, pbe_param, |
1150 | 0 | NSSPKCS5V2PBEParameterTemplate, |
1151 | 0 | &pbev2_param.keyParams.parameters); |
1152 | 0 | if (rv != SECSuccess) { |
1153 | 0 | break; |
1154 | 0 | } |
1155 | 0 | pbe_param->keyLen = DER_GetInteger(&pbe_param->keyLength); |
1156 | 0 | } |
1157 | | /* we we are encrypting, save any iv's */ |
1158 | 0 | if (algorithm == SEC_OID_PKCS5_PBES2) { |
1159 | 0 | pbe_param->ivLen = pbev2_param.algParams.parameters.len; |
1160 | 0 | pbe_param->ivData = pbev2_param.algParams.parameters.data; |
1161 | 0 | } |
1162 | 0 | pbe_param->hashType = |
1163 | 0 | HASH_FromHMACOid(SECOID_GetAlgorithmTag(&pbe_param->prfAlg)); |
1164 | 0 | if (pbe_param->hashType == HASH_AlgNULL) { |
1165 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
1166 | 0 | rv = SECFailure; |
1167 | 0 | } |
1168 | 0 | break; |
1169 | 0 | } |
1170 | | |
1171 | 0 | loser: |
1172 | 0 | PORT_Memset(&pbev2_param, 0, sizeof(pbev2_param)); |
1173 | 0 | if (rv == SECSuccess) { |
1174 | 0 | pbe_param->iter = DER_GetInteger(&pbe_param->iteration); |
1175 | 0 | } else { |
1176 | 0 | nsspkcs5_DestroyPBEParameter(pbe_param); |
1177 | 0 | pbe_param = NULL; |
1178 | 0 | } |
1179 | |
|
1180 | 0 | return pbe_param; |
1181 | 0 | } |
1182 | | |
1183 | | /* destroy a pbe parameter. it assumes that the parameter was |
1184 | | * generated using the appropriate create function and therefor |
1185 | | * contains an arena pool. |
1186 | | */ |
1187 | | void |
1188 | | nsspkcs5_DestroyPBEParameter(NSSPKCS5PBEParameter *pbe_param) |
1189 | 0 | { |
1190 | 0 | if (pbe_param != NULL) { |
1191 | 0 | PORT_FreeArena(pbe_param->poolp, PR_TRUE); |
1192 | 0 | } |
1193 | 0 | } |
1194 | | |
1195 | | /* crypto routines */ |
1196 | | /* perform DES encryption and decryption. these routines are called |
1197 | | * by nsspkcs5_CipherData. In the case of an error, NULL is returned. |
1198 | | */ |
1199 | | static SECItem * |
1200 | | sec_pkcs5_des(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, |
1201 | | PRBool encrypt) |
1202 | 0 | { |
1203 | 0 | SECItem *dest; |
1204 | 0 | SECItem *dup_src; |
1205 | 0 | CK_RV crv = CKR_DEVICE_ERROR; |
1206 | 0 | int error; |
1207 | 0 | SECStatus rv = SECFailure; |
1208 | 0 | DESContext *ctxt; |
1209 | 0 | unsigned int pad; |
1210 | |
|
1211 | 0 | if ((src == NULL) || (key == NULL) || (iv == NULL)) { |
1212 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1213 | 0 | return NULL; |
1214 | 0 | } |
1215 | | |
1216 | 0 | dup_src = SECITEM_DupItem(src); |
1217 | 0 | if (dup_src == NULL) { |
1218 | 0 | return NULL; |
1219 | 0 | } |
1220 | | |
1221 | 0 | if (encrypt != PR_FALSE) { |
1222 | 0 | void *dummy; |
1223 | |
|
1224 | 0 | dummy = CBC_PadBuffer(NULL, dup_src->data, |
1225 | 0 | dup_src->len, &dup_src->len, DES_BLOCK_SIZE); |
1226 | 0 | if (dummy == NULL) { |
1227 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1228 | 0 | return NULL; |
1229 | 0 | } |
1230 | 0 | dup_src->data = (unsigned char *)dummy; |
1231 | 0 | } |
1232 | | |
1233 | 0 | dest = SECITEM_AllocItem(NULL, NULL, dup_src->len + MAX_CRYPTO_EXPANSION); |
1234 | 0 | if (dest == NULL) { |
1235 | 0 | goto loser; |
1236 | 0 | } |
1237 | 0 | ctxt = DES_CreateContext(key->data, iv->data, |
1238 | 0 | (triple_des ? NSS_DES_EDE3_CBC : NSS_DES_CBC), |
1239 | 0 | encrypt); |
1240 | 0 | if (ctxt == NULL) { |
1241 | 0 | goto loser; |
1242 | 0 | } |
1243 | 0 | rv = (encrypt ? DES_Encrypt : DES_Decrypt)( |
1244 | 0 | ctxt, dest->data, &dest->len, |
1245 | 0 | dest->len, dup_src->data, dup_src->len); |
1246 | |
|
1247 | 0 | crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; |
1248 | 0 | error = PORT_GetError(); |
1249 | | |
1250 | | /* remove padding */ |
1251 | 0 | if ((encrypt == PR_FALSE) && (rv == SECSuccess)) { |
1252 | 0 | crv = sftk_CheckCBCPadding(dest->data, dest->len, DES_BLOCK_SIZE, &pad); |
1253 | 0 | dest->len = PORT_CT_SEL(sftk_CKRVToMask(crv), dest->len - pad, dest->len); |
1254 | 0 | PORT_SetError(PORT_CT_SEL(sftk_CKRVToMask(crv), error, SEC_ERROR_BAD_PASSWORD)); |
1255 | 0 | } |
1256 | 0 | DES_DestroyContext(ctxt, PR_TRUE); |
1257 | |
|
1258 | 0 | loser: |
1259 | 0 | if (crv != CKR_OK) { |
1260 | 0 | if (dest != NULL) { |
1261 | 0 | SECITEM_ZfreeItem(dest, PR_TRUE); |
1262 | 0 | } |
1263 | 0 | dest = NULL; |
1264 | 0 | } |
1265 | |
|
1266 | 0 | if (dup_src != NULL) { |
1267 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1268 | 0 | } |
1269 | |
|
1270 | 0 | return dest; |
1271 | 0 | } |
1272 | | |
1273 | | /* perform aes encryption/decryption if an error occurs, NULL is returned |
1274 | | */ |
1275 | | static SECItem * |
1276 | | sec_pkcs5_aes(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, |
1277 | | PRBool encrypt) |
1278 | 0 | { |
1279 | 0 | SECItem *dest; |
1280 | 0 | SECItem *dup_src; |
1281 | 0 | CK_RV crv = CKR_DEVICE_ERROR; |
1282 | 0 | int error; |
1283 | 0 | SECStatus rv = SECFailure; |
1284 | 0 | AESContext *ctxt; |
1285 | 0 | unsigned int pad; |
1286 | |
|
1287 | 0 | if ((src == NULL) || (key == NULL) || (iv == NULL)) { |
1288 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1289 | 0 | return NULL; |
1290 | 0 | } |
1291 | | |
1292 | 0 | dup_src = SECITEM_DupItem(src); |
1293 | 0 | if (dup_src == NULL) { |
1294 | 0 | return NULL; |
1295 | 0 | } |
1296 | | |
1297 | 0 | if (encrypt != PR_FALSE) { |
1298 | 0 | void *dummy; |
1299 | |
|
1300 | 0 | dummy = CBC_PadBuffer(NULL, dup_src->data, |
1301 | 0 | dup_src->len, &dup_src->len, AES_BLOCK_SIZE); |
1302 | 0 | if (dummy == NULL) { |
1303 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1304 | 0 | return NULL; |
1305 | 0 | } |
1306 | 0 | dup_src->data = (unsigned char *)dummy; |
1307 | 0 | } |
1308 | | |
1309 | 0 | dest = SECITEM_AllocItem(NULL, NULL, dup_src->len + MAX_CRYPTO_EXPANSION); |
1310 | 0 | if (dest == NULL) { |
1311 | 0 | goto loser; |
1312 | 0 | } |
1313 | 0 | ctxt = AES_CreateContext(key->data, iv->data, NSS_AES_CBC, |
1314 | 0 | encrypt, key->len, AES_BLOCK_SIZE); |
1315 | 0 | if (ctxt == NULL) { |
1316 | 0 | goto loser; |
1317 | 0 | } |
1318 | 0 | rv = (encrypt ? AES_Encrypt : AES_Decrypt)( |
1319 | 0 | ctxt, dest->data, &dest->len, |
1320 | 0 | dest->len, dup_src->data, dup_src->len); |
1321 | |
|
1322 | 0 | crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; |
1323 | 0 | error = PORT_GetError(); |
1324 | | |
1325 | | /* remove padding */ |
1326 | 0 | if ((encrypt == PR_FALSE) && (rv == SECSuccess)) { |
1327 | 0 | crv = sftk_CheckCBCPadding(dest->data, dest->len, AES_BLOCK_SIZE, &pad); |
1328 | 0 | dest->len = PORT_CT_SEL(sftk_CKRVToMask(crv), dest->len - pad, dest->len); |
1329 | 0 | PORT_SetError(PORT_CT_SEL(sftk_CKRVToMask(crv), error, SEC_ERROR_BAD_PASSWORD)); |
1330 | 0 | } |
1331 | 0 | AES_DestroyContext(ctxt, PR_TRUE); |
1332 | |
|
1333 | 0 | loser: |
1334 | 0 | if (crv != CKR_OK) { |
1335 | 0 | if (dest != NULL) { |
1336 | 0 | SECITEM_ZfreeItem(dest, PR_TRUE); |
1337 | 0 | } |
1338 | 0 | dest = NULL; |
1339 | 0 | } |
1340 | |
|
1341 | 0 | if (dup_src != NULL) { |
1342 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1343 | 0 | } |
1344 | |
|
1345 | 0 | return dest; |
1346 | 0 | } |
1347 | | |
1348 | | /* perform aes encryption/decryption if an error occurs, NULL is returned |
1349 | | */ |
1350 | | static SECItem * |
1351 | | sec_pkcs5_aes_key_wrap(SECItem *key, SECItem *iv, SECItem *src, PRBool triple_des, |
1352 | | PRBool encrypt) |
1353 | 0 | { |
1354 | 0 | SECItem *dest; |
1355 | 0 | SECItem *dup_src; |
1356 | 0 | CK_RV crv = CKR_DEVICE_ERROR; |
1357 | 0 | int error; |
1358 | 0 | SECStatus rv = SECFailure; |
1359 | 0 | AESKeyWrapContext *ctxt; |
1360 | 0 | unsigned int pad; |
1361 | |
|
1362 | 0 | if ((src == NULL) || (key == NULL) || (iv == NULL)) { |
1363 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1364 | 0 | return NULL; |
1365 | 0 | } |
1366 | | |
1367 | 0 | dup_src = SECITEM_DupItem(src); |
1368 | 0 | if (dup_src == NULL) { |
1369 | 0 | return NULL; |
1370 | 0 | } |
1371 | | |
1372 | 0 | if (encrypt != PR_FALSE) { |
1373 | 0 | void *dummy; |
1374 | |
|
1375 | 0 | dummy = CBC_PadBuffer(NULL, dup_src->data, |
1376 | 0 | dup_src->len, &dup_src->len, AES_BLOCK_SIZE); |
1377 | 0 | if (dummy == NULL) { |
1378 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1379 | 0 | return NULL; |
1380 | 0 | } |
1381 | 0 | dup_src->data = (unsigned char *)dummy; |
1382 | 0 | } |
1383 | | |
1384 | 0 | dest = SECITEM_AllocItem(NULL, NULL, dup_src->len + MAX_CRYPTO_EXPANSION); |
1385 | 0 | if (dest == NULL) { |
1386 | 0 | goto loser; |
1387 | 0 | } |
1388 | 0 | ctxt = AESKeyWrap_CreateContext(key->data, iv->data, encrypt, |
1389 | 0 | key->len); |
1390 | |
|
1391 | 0 | if (ctxt == NULL) { |
1392 | 0 | goto loser; |
1393 | 0 | } |
1394 | 0 | rv = (encrypt ? AESKeyWrap_Encrypt : AESKeyWrap_Decrypt)( |
1395 | 0 | ctxt, dest->data, &dest->len, |
1396 | 0 | dest->len, dup_src->data, dup_src->len); |
1397 | |
|
1398 | 0 | crv = (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; |
1399 | 0 | error = PORT_GetError(); |
1400 | | |
1401 | | /* remove padding */ |
1402 | 0 | if ((encrypt == PR_FALSE) && (rv == SECSuccess)) { |
1403 | 0 | crv = sftk_CheckCBCPadding(dest->data, dest->len, AES_BLOCK_SIZE, &pad); |
1404 | 0 | dest->len = PORT_CT_SEL(sftk_CKRVToMask(crv), dest->len - pad, dest->len); |
1405 | 0 | PORT_SetError(PORT_CT_SEL(sftk_CKRVToMask(crv), error, SEC_ERROR_BAD_PASSWORD)); |
1406 | 0 | } |
1407 | 0 | AESKeyWrap_DestroyContext(ctxt, PR_TRUE); |
1408 | |
|
1409 | 0 | loser: |
1410 | 0 | if (crv != CKR_OK) { |
1411 | 0 | if (dest != NULL) { |
1412 | 0 | SECITEM_ZfreeItem(dest, PR_TRUE); |
1413 | 0 | } |
1414 | 0 | dest = NULL; |
1415 | 0 | } |
1416 | |
|
1417 | 0 | if (dup_src != NULL) { |
1418 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1419 | 0 | } |
1420 | |
|
1421 | 0 | return dest; |
1422 | 0 | } |
1423 | | |
1424 | | #ifndef NSS_DISABLE_DEPRECATED_RC2 |
1425 | | /* perform rc2 encryption/decryption if an error occurs, NULL is returned |
1426 | | */ |
1427 | | static SECItem * |
1428 | | sec_pkcs5_rc2(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy, |
1429 | | PRBool encrypt) |
1430 | 0 | { |
1431 | 0 | SECItem *dest; |
1432 | 0 | SECItem *dup_src; |
1433 | 0 | SECStatus rv = SECFailure; |
1434 | 0 | int pad; |
1435 | |
|
1436 | 0 | if ((src == NULL) || (key == NULL) || (iv == NULL)) { |
1437 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1438 | 0 | return NULL; |
1439 | 0 | } |
1440 | | |
1441 | 0 | dup_src = SECITEM_DupItem(src); |
1442 | 0 | if (dup_src == NULL) { |
1443 | 0 | return NULL; |
1444 | 0 | } |
1445 | | |
1446 | 0 | if (encrypt != PR_FALSE) { |
1447 | 0 | void *v; |
1448 | |
|
1449 | 0 | v = CBC_PadBuffer(NULL, dup_src->data, |
1450 | 0 | dup_src->len, &dup_src->len, 8 /* RC2_BLOCK_SIZE */); |
1451 | 0 | if (v == NULL) { |
1452 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1453 | 0 | return NULL; |
1454 | 0 | } |
1455 | 0 | dup_src->data = (unsigned char *)v; |
1456 | 0 | } |
1457 | | |
1458 | 0 | dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
1459 | 0 | if (dest != NULL) { |
1460 | 0 | dest->data = (unsigned char *)PORT_ZAlloc(dup_src->len + 64); |
1461 | 0 | if (dest->data != NULL) { |
1462 | 0 | RC2Context *ctxt; |
1463 | |
|
1464 | 0 | ctxt = RC2_CreateContext(key->data, key->len, iv->data, |
1465 | 0 | NSS_RC2_CBC, key->len); |
1466 | |
|
1467 | 0 | if (ctxt != NULL) { |
1468 | 0 | rv = (encrypt ? RC2_Encrypt : RC2_Decrypt)( |
1469 | 0 | ctxt, dest->data, &dest->len, |
1470 | 0 | dup_src->len + 64, dup_src->data, dup_src->len); |
1471 | | |
1472 | | /* assumes 8 byte blocks -- remove padding */ |
1473 | 0 | if ((rv == SECSuccess) && (encrypt != PR_TRUE)) { |
1474 | 0 | pad = dest->data[dest->len - 1]; |
1475 | 0 | if ((pad > 0) && (pad <= 8)) { |
1476 | 0 | if (dest->data[dest->len - pad] != pad) { |
1477 | 0 | PORT_SetError(SEC_ERROR_BAD_PASSWORD); |
1478 | 0 | rv = SECFailure; |
1479 | 0 | } else { |
1480 | 0 | dest->len -= pad; |
1481 | 0 | } |
1482 | 0 | } else { |
1483 | 0 | PORT_SetError(SEC_ERROR_BAD_PASSWORD); |
1484 | 0 | rv = SECFailure; |
1485 | 0 | } |
1486 | 0 | } |
1487 | 0 | } |
1488 | 0 | } |
1489 | 0 | } |
1490 | |
|
1491 | 0 | if ((rv != SECSuccess) && (dest != NULL)) { |
1492 | 0 | SECITEM_ZfreeItem(dest, PR_TRUE); |
1493 | 0 | dest = NULL; |
1494 | 0 | } |
1495 | |
|
1496 | 0 | if (dup_src != NULL) { |
1497 | 0 | SECITEM_ZfreeItem(dup_src, PR_TRUE); |
1498 | 0 | } |
1499 | |
|
1500 | 0 | return dest; |
1501 | 0 | } |
1502 | | #endif /* NSS_DISABLE_DEPRECATED_RC2 */ |
1503 | | |
1504 | | /* perform rc4 encryption and decryption */ |
1505 | | static SECItem * |
1506 | | sec_pkcs5_rc4(SECItem *key, SECItem *iv, SECItem *src, PRBool dummy_op, |
1507 | | PRBool encrypt) |
1508 | 0 | { |
1509 | 0 | SECItem *dest; |
1510 | 0 | SECStatus rv = SECFailure; |
1511 | |
|
1512 | 0 | if ((src == NULL) || (key == NULL) || (iv == NULL)) { |
1513 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1514 | 0 | return NULL; |
1515 | 0 | } |
1516 | | |
1517 | 0 | dest = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
1518 | 0 | if (dest != NULL) { |
1519 | 0 | dest->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * |
1520 | 0 | (src->len + 64)); |
1521 | 0 | if (dest->data != NULL) { |
1522 | 0 | RC4Context *ctxt; |
1523 | |
|
1524 | 0 | ctxt = RC4_CreateContext(key->data, key->len); |
1525 | 0 | if (ctxt) { |
1526 | 0 | rv = (encrypt ? RC4_Encrypt : RC4_Decrypt)( |
1527 | 0 | ctxt, dest->data, &dest->len, |
1528 | 0 | src->len + 64, src->data, src->len); |
1529 | 0 | RC4_DestroyContext(ctxt, PR_TRUE); |
1530 | 0 | } |
1531 | 0 | } |
1532 | 0 | } |
1533 | |
|
1534 | 0 | if ((rv != SECSuccess) && (dest)) { |
1535 | 0 | SECITEM_ZfreeItem(dest, PR_TRUE); |
1536 | 0 | dest = NULL; |
1537 | 0 | } |
1538 | |
|
1539 | 0 | return dest; |
1540 | 0 | } |
1541 | | /* function pointer template for crypto functions */ |
1542 | | typedef SECItem *(*pkcs5_crypto_func)(SECItem *key, SECItem *iv, |
1543 | | SECItem *src, PRBool op1, PRBool op2); |
1544 | | |
1545 | | /* performs the cipher operation on the src and returns the result. |
1546 | | * if an error occurs, NULL is returned. |
1547 | | * |
1548 | | * a null length password is allowed. this corresponds to encrypting |
1549 | | * the data with ust the salt. |
1550 | | */ |
1551 | | /* change this to use PKCS 11? */ |
1552 | | SECItem * |
1553 | | nsspkcs5_CipherData(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, |
1554 | | SECItem *src, PRBool encrypt, PRBool *update) |
1555 | 0 | { |
1556 | 0 | SECItem *key = NULL, iv; |
1557 | 0 | SECItem *dest = NULL; |
1558 | 0 | PRBool tripleDES = PR_TRUE; |
1559 | 0 | pkcs5_crypto_func cryptof; |
1560 | |
|
1561 | 0 | iv.data = NULL; |
1562 | |
|
1563 | 0 | if (update) { |
1564 | 0 | *update = PR_FALSE; |
1565 | 0 | } |
1566 | |
|
1567 | 0 | if ((pwitem == NULL) || (src == NULL)) { |
1568 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1569 | 0 | return NULL; |
1570 | 0 | } |
1571 | | |
1572 | | /* get key, and iv */ |
1573 | 0 | key = nsspkcs5_ComputeKeyAndIV(pbe_param, pwitem, &iv, PR_FALSE); |
1574 | 0 | if (key == NULL) { |
1575 | 0 | return NULL; |
1576 | 0 | } |
1577 | | |
1578 | 0 | switch (pbe_param->encAlg) { |
1579 | | /* PKCS 5 v2 only */ |
1580 | 0 | case SEC_OID_AES_128_KEY_WRAP: |
1581 | 0 | case SEC_OID_AES_192_KEY_WRAP: |
1582 | 0 | case SEC_OID_AES_256_KEY_WRAP: |
1583 | 0 | cryptof = sec_pkcs5_aes_key_wrap; |
1584 | 0 | break; |
1585 | 0 | case SEC_OID_AES_128_CBC: |
1586 | 0 | case SEC_OID_AES_192_CBC: |
1587 | 0 | case SEC_OID_AES_256_CBC: |
1588 | 0 | cryptof = sec_pkcs5_aes; |
1589 | 0 | break; |
1590 | 0 | case SEC_OID_DES_EDE3_CBC: |
1591 | 0 | cryptof = sec_pkcs5_des; |
1592 | 0 | tripleDES = PR_TRUE; |
1593 | 0 | break; |
1594 | 0 | case SEC_OID_DES_CBC: |
1595 | 0 | cryptof = sec_pkcs5_des; |
1596 | 0 | tripleDES = PR_FALSE; |
1597 | 0 | break; |
1598 | 0 | #ifndef NSS_DISABLE_DEPRECATED_RC2 |
1599 | 0 | case SEC_OID_RC2_CBC: |
1600 | 0 | cryptof = sec_pkcs5_rc2; |
1601 | 0 | break; |
1602 | 0 | #endif |
1603 | 0 | case SEC_OID_RC4: |
1604 | 0 | cryptof = sec_pkcs5_rc4; |
1605 | 0 | break; |
1606 | 0 | default: |
1607 | 0 | cryptof = NULL; |
1608 | 0 | break; |
1609 | 0 | } |
1610 | | |
1611 | 0 | if (cryptof == NULL) { |
1612 | 0 | goto loser; |
1613 | 0 | } |
1614 | | |
1615 | 0 | dest = (*cryptof)(key, &iv, src, tripleDES, encrypt); |
1616 | | /* |
1617 | | * it's possible for some keys and keydb's to claim to |
1618 | | * be triple des when they're really des. In this case |
1619 | | * we simply try des. If des works we set the update flag |
1620 | | * so the key db knows it needs to update all it's entries. |
1621 | | * The case can only happen on decrypted of a |
1622 | | * SEC_OID_DES_EDE3_CBD. |
1623 | | */ |
1624 | 0 | if ((pbe_param->encAlg == SEC_OID_DES_EDE3_CBC) && |
1625 | 0 | (dest == NULL) && (encrypt == PR_FALSE)) { |
1626 | 0 | dest = (*cryptof)(key, &iv, src, PR_FALSE, encrypt); |
1627 | 0 | if (update && (dest != NULL)) |
1628 | 0 | *update = PR_TRUE; |
1629 | 0 | } |
1630 | |
|
1631 | 0 | loser: |
1632 | 0 | if (key != NULL) { |
1633 | 0 | SECITEM_ZfreeItem(key, PR_TRUE); |
1634 | 0 | } |
1635 | 0 | if (iv.data != NULL) { |
1636 | 0 | SECITEM_ZfreeItem(&iv, PR_FALSE); |
1637 | 0 | } |
1638 | |
|
1639 | 0 | return dest; |
1640 | 0 | } |
1641 | | |
1642 | | /* creates a algorithm ID containing the PBE algorithm and appropriate |
1643 | | * parameters. the required parameter is the algorithm. if salt is |
1644 | | * not specified, it is generated randomly. if IV is specified, it overrides |
1645 | | * the PKCS 5 generation of the IV. |
1646 | | * |
1647 | | * the returned SECAlgorithmID should be destroyed using |
1648 | | * SECOID_DestroyAlgorithmID |
1649 | | */ |
1650 | | SECAlgorithmID * |
1651 | | nsspkcs5_CreateAlgorithmID(PLArenaPool *arena, SECOidTag algorithm, |
1652 | | NSSPKCS5PBEParameter *pbe_param) |
1653 | 0 | { |
1654 | 0 | SECAlgorithmID *algid, *ret_algid = NULL; |
1655 | 0 | SECItem der_param; |
1656 | 0 | nsspkcs5V2PBEParameter pkcs5v2_param; |
1657 | |
|
1658 | 0 | SECStatus rv = SECFailure; |
1659 | 0 | void *dummy = NULL; |
1660 | |
|
1661 | 0 | if (arena == NULL) { |
1662 | 0 | return NULL; |
1663 | 0 | } |
1664 | | |
1665 | 0 | der_param.data = NULL; |
1666 | 0 | der_param.len = 0; |
1667 | | |
1668 | | /* generate the algorithm id */ |
1669 | 0 | algid = (SECAlgorithmID *)PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); |
1670 | 0 | if (algid == NULL) { |
1671 | 0 | goto loser; |
1672 | 0 | } |
1673 | | |
1674 | 0 | if (pbe_param->iteration.data == NULL) { |
1675 | 0 | dummy = SEC_ASN1EncodeInteger(pbe_param->poolp, &pbe_param->iteration, |
1676 | 0 | pbe_param->iter); |
1677 | 0 | if (dummy == NULL) { |
1678 | 0 | goto loser; |
1679 | 0 | } |
1680 | 0 | } |
1681 | 0 | switch (pbe_param->pbeType) { |
1682 | 0 | case NSSPKCS5_PBKDF1: |
1683 | 0 | dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param, |
1684 | 0 | NSSPKCS5PBEParameterTemplate); |
1685 | 0 | break; |
1686 | 0 | case NSSPKCS5_PKCS12_V2: |
1687 | 0 | dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param, |
1688 | 0 | NSSPKCS5PKCS12V2PBEParameterTemplate); |
1689 | 0 | break; |
1690 | 0 | case NSSPKCS5_PBKDF2: |
1691 | 0 | if (pbe_param->keyLength.data == NULL) { |
1692 | 0 | dummy = SEC_ASN1EncodeInteger(pbe_param->poolp, |
1693 | 0 | &pbe_param->keyLength, pbe_param->keyLen); |
1694 | 0 | if (dummy == NULL) { |
1695 | 0 | goto loser; |
1696 | 0 | } |
1697 | 0 | } |
1698 | 0 | PORT_Memset(&pkcs5v2_param, 0, sizeof(pkcs5v2_param)); |
1699 | 0 | dummy = SEC_ASN1EncodeItem(arena, &der_param, pbe_param, |
1700 | 0 | NSSPKCS5V2PBEParameterTemplate); |
1701 | 0 | if (dummy == NULL) { |
1702 | 0 | break; |
1703 | 0 | } |
1704 | 0 | dummy = NULL; |
1705 | 0 | rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.keyParams, |
1706 | 0 | SEC_OID_PKCS5_PBKDF2, &der_param); |
1707 | 0 | if (rv != SECSuccess) { |
1708 | 0 | break; |
1709 | 0 | } |
1710 | 0 | der_param.data = pbe_param->ivData; |
1711 | 0 | der_param.len = pbe_param->ivLen; |
1712 | 0 | rv = SECOID_SetAlgorithmID(arena, &pkcs5v2_param.algParams, |
1713 | 0 | pbe_param->encAlg, pbe_param->ivLen ? &der_param : NULL); |
1714 | 0 | if (rv != SECSuccess) { |
1715 | 0 | dummy = NULL; |
1716 | 0 | break; |
1717 | 0 | } |
1718 | 0 | der_param.data = NULL; |
1719 | 0 | der_param.len = 0; |
1720 | 0 | dummy = SEC_ASN1EncodeItem(arena, &der_param, &pkcs5v2_param, |
1721 | 0 | NSSPKCS5V2PBES2ParameterTemplate); |
1722 | | /* If the algorithm was set to some encryption oid, set it |
1723 | | * to PBES2 */ |
1724 | 0 | if ((algorithm != SEC_OID_PKCS5_PBKDF2) && |
1725 | 0 | (algorithm != SEC_OID_PKCS5_PBMAC1)) { |
1726 | 0 | algorithm = SEC_OID_PKCS5_PBES2; |
1727 | 0 | } |
1728 | 0 | break; |
1729 | 0 | default: |
1730 | 0 | break; |
1731 | 0 | } |
1732 | | |
1733 | 0 | if (dummy == NULL) { |
1734 | 0 | goto loser; |
1735 | 0 | } |
1736 | | |
1737 | 0 | rv = SECOID_SetAlgorithmID(arena, algid, algorithm, &der_param); |
1738 | 0 | if (rv != SECSuccess) { |
1739 | 0 | goto loser; |
1740 | 0 | } |
1741 | | |
1742 | 0 | ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID)); |
1743 | 0 | if (ret_algid == NULL) { |
1744 | 0 | goto loser; |
1745 | 0 | } |
1746 | | |
1747 | 0 | rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid); |
1748 | 0 | if (rv != SECSuccess) { |
1749 | 0 | SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE); |
1750 | 0 | ret_algid = NULL; |
1751 | 0 | } |
1752 | |
|
1753 | 0 | loser: |
1754 | |
|
1755 | 0 | return ret_algid; |
1756 | 0 | } |
1757 | | |
1758 | 0 | #define TEST_KEY "pbkdf test key" |
1759 | | SECStatus |
1760 | | sftk_fips_pbkdf_PowerUpSelfTests(void) |
1761 | 0 | { |
1762 | 0 | SECItem *result; |
1763 | 0 | SECItem inKey; |
1764 | 0 | NSSPKCS5PBEParameter pbe_params; |
1765 | 0 | unsigned char iteration_count = 5; |
1766 | 0 | unsigned char keyLen = 64; |
1767 | 0 | char *inKeyData = TEST_KEY; |
1768 | 0 | static const unsigned char saltData[] = { |
1769 | 0 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
1770 | 0 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f |
1771 | 0 | }; |
1772 | |
|
1773 | 0 | static const unsigned char pbkdf_known_answer[] = { |
1774 | 0 | 0x73, 0x8c, 0xfa, 0x02, 0xe8, 0xdb, 0x43, 0xe4, |
1775 | 0 | 0x99, 0xc5, 0xfd, 0xd9, 0x4d, 0x8e, 0x3e, 0x7b, |
1776 | 0 | 0xc4, 0xda, 0x22, 0x1b, 0xe1, 0xae, 0x23, 0x7a, |
1777 | 0 | 0x21, 0x27, 0xbd, 0xcc, 0x78, 0xc4, 0xe6, 0xc5, |
1778 | 0 | 0x33, 0x38, 0x35, 0xe0, 0x68, 0x1a, 0x1e, 0x06, |
1779 | 0 | 0xad, 0xaf, 0x7f, 0xd7, 0x3f, 0x0e, 0xc0, 0x90, |
1780 | 0 | 0x17, 0x97, 0x73, 0x75, 0x7b, 0x88, 0x49, 0xd8, |
1781 | 0 | 0x6f, 0x78, 0x5a, 0xde, 0x50, 0x20, 0x55, 0x33 |
1782 | 0 | }; |
1783 | |
|
1784 | 0 | sftk_PBELockInit(); |
1785 | |
|
1786 | 0 | inKey.data = (unsigned char *)inKeyData; |
1787 | 0 | inKey.len = sizeof(TEST_KEY) - 1; |
1788 | |
|
1789 | 0 | pbe_params.salt.data = (unsigned char *)saltData; |
1790 | 0 | pbe_params.salt.len = sizeof(saltData); |
1791 | | /* the interation and keyLength are used as intermediate |
1792 | | * values when decoding the Algorithm ID, set them for completeness, |
1793 | | * but they are not used */ |
1794 | 0 | pbe_params.iteration.data = &iteration_count; |
1795 | 0 | pbe_params.iteration.len = 1; |
1796 | 0 | pbe_params.keyLength.data = &keyLen; |
1797 | 0 | pbe_params.keyLength.len = 1; |
1798 | | /* pkcs5v2 stores the key in the AlgorithmID, so we don't need to |
1799 | | * generate it here */ |
1800 | 0 | pbe_params.ivLen = 0; |
1801 | 0 | pbe_params.ivData = NULL; |
1802 | | /* keyID is only used by pkcs12 extensions to pkcs5v1 */ |
1803 | 0 | pbe_params.keyID = pbeBitGenCipherKey; |
1804 | | /* Algorithm is used by the decryption code after get get our key */ |
1805 | 0 | pbe_params.encAlg = SEC_OID_AES_256_CBC; |
1806 | | /* these are the fields actually used in nsspkcs5_ComputeKeyAndIV |
1807 | | * for NSSPKCS5_PBKDF2 */ |
1808 | 0 | pbe_params.iter = iteration_count; |
1809 | 0 | pbe_params.keyLen = keyLen; |
1810 | 0 | pbe_params.hashType = HASH_AlgSHA256; |
1811 | 0 | pbe_params.pbeType = NSSPKCS5_PBKDF2; |
1812 | 0 | pbe_params.is2KeyDES = PR_FALSE; |
1813 | |
|
1814 | 0 | result = nsspkcs5_ComputeKeyAndIV(&pbe_params, &inKey, NULL, PR_FALSE); |
1815 | 0 | if ((result == NULL) || (result->len != sizeof(pbkdf_known_answer)) || |
1816 | 0 | (PORT_Memcmp(result->data, pbkdf_known_answer, sizeof(pbkdf_known_answer)) != 0)) { |
1817 | 0 | SECITEM_FreeItem(result, PR_TRUE); |
1818 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
1819 | 0 | return SECFailure; |
1820 | 0 | } |
1821 | 0 | SECITEM_FreeItem(result, PR_TRUE); |
1822 | 0 | return SECSuccess; |
1823 | 0 | } |