]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | /* | |
25 | * pkc12Crypto.cpp - PKCS12-specific cyptrographic routines | |
26 | */ | |
27 | ||
28 | #include "pkcs12Crypto.h" | |
29 | #include "pkcs12Utils.h" | |
30 | #include "pkcs12Debug.h" | |
31 | #include <security_cdsa_utils/cuCdsaUtils.h> | |
32 | #include <security_cdsa_utilities/cssmacl.h> | |
33 | #include <security_keychain/Access.h> | |
34 | ||
35 | /* | |
36 | * Given appropriate P12-style parameters, cook up a CSSM_KEY. | |
37 | * Caller MUST CSSM_FreeKey() when it's done with the key. | |
38 | */ | |
39 | #define KEY_LABEL "p12 key" | |
40 | ||
41 | CSSM_RETURN p12KeyGen( | |
42 | CSSM_CSP_HANDLE cspHand, | |
43 | CSSM_KEY &key, | |
44 | bool isForEncr, // true: en/decrypt false: MAC | |
45 | CSSM_ALGORITHMS keyAlg, | |
46 | CSSM_ALGORITHMS pbeHashAlg, // actually must be SHA1 for now | |
47 | uint32 keySizeInBits, | |
48 | uint32 iterCount, | |
49 | const CSSM_DATA &salt, | |
50 | /* exactly one of the following two must be valid */ | |
51 | const CSSM_DATA *pwd, // unicode external representation | |
52 | const CSSM_KEY *passKey, | |
53 | CSSM_DATA &iv) // referent is optional | |
54 | { | |
55 | CSSM_RETURN crtn; | |
56 | CSSM_CC_HANDLE ccHand; | |
57 | CSSM_DATA dummyLabel; | |
58 | CSSM_ACCESS_CREDENTIALS creds; | |
59 | ||
60 | memset(&key, 0, sizeof(CSSM_KEY)); | |
61 | memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); | |
62 | ||
63 | /* infer key derivation algorithm */ | |
64 | CSSM_ALGORITHMS deriveAlg = CSSM_ALGID_NONE; | |
65 | if(pbeHashAlg != CSSM_ALGID_SHA1) { | |
66 | return CSSMERR_CSP_INVALID_ALGORITHM; | |
67 | } | |
68 | if(isForEncr) { | |
69 | /* | |
70 | * FIXME - if this key is going to be used to wrap/unwrap a | |
71 | * shrouded key bag, its usage will change accordingly... | |
72 | */ | |
73 | deriveAlg = CSSM_ALGID_PKCS12_PBE_ENCR; | |
74 | } | |
75 | else { | |
76 | deriveAlg = CSSM_ALGID_PKCS12_PBE_MAC; | |
77 | } | |
78 | CSSM_CRYPTO_DATA seed; | |
79 | if(pwd) { | |
80 | seed.Param = *pwd; | |
81 | } | |
82 | else { | |
83 | seed.Param.Data = NULL; | |
84 | seed.Param.Length = 0; | |
85 | } | |
86 | seed.Callback = NULL; | |
87 | seed.CallerCtx = NULL; | |
88 | ||
89 | crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand, | |
90 | deriveAlg, | |
91 | keyAlg, | |
92 | keySizeInBits, | |
93 | &creds, | |
94 | passKey, // BaseKey | |
95 | iterCount, | |
96 | &salt, | |
97 | &seed, // seed | |
98 | &ccHand); | |
99 | if(crtn) { | |
100 | p12LogCssmError("CSSM_CSP_CreateDeriveKeyContext", crtn); | |
101 | return crtn; | |
102 | } | |
103 | ||
104 | dummyLabel.Length = strlen(KEY_LABEL); | |
105 | dummyLabel.Data = (uint8 *)KEY_LABEL; | |
106 | ||
107 | /* KEYUSE_ANY - this is just an ephemeral session key */ | |
108 | crtn = CSSM_DeriveKey(ccHand, | |
109 | &iv, | |
110 | CSSM_KEYUSE_ANY, | |
111 | CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, | |
112 | &dummyLabel, | |
113 | NULL, // cred and acl | |
114 | &key); | |
115 | CSSM_DeleteContext(ccHand); | |
116 | if(crtn) { | |
117 | p12LogCssmError("CSSM_DeriveKey", crtn); | |
118 | } | |
119 | return crtn; | |
120 | } | |
121 | ||
122 | /* | |
123 | * Decrypt (typically, an encrypted P7 ContentInfo contents) | |
124 | */ | |
125 | CSSM_RETURN p12Decrypt( | |
126 | CSSM_CSP_HANDLE cspHand, | |
127 | const CSSM_DATA &cipherText, | |
128 | CSSM_ALGORITHMS keyAlg, | |
129 | CSSM_ALGORITHMS encrAlg, | |
130 | CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only | |
131 | uint32 keySizeInBits, | |
132 | uint32 blockSizeInBytes, // for IV | |
133 | CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. | |
134 | CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. | |
135 | uint32 iterCount, | |
136 | const CSSM_DATA &salt, | |
137 | /* exactly one of the following two must be valid */ | |
138 | const CSSM_DATA *pwd, // unicode external representation | |
139 | const CSSM_KEY *passKey, | |
140 | SecNssCoder &coder, // for mallocing plainText | |
141 | CSSM_DATA &plainText) | |
142 | { | |
143 | CSSM_RETURN crtn; | |
144 | CSSM_KEY ckey; | |
145 | CSSM_CC_HANDLE ccHand = 0; | |
146 | CSSM_DATA ourPtext = {0, NULL}; | |
147 | CSSM_DATA remData = {0, NULL}; | |
148 | ||
149 | /* P12 style IV derivation, optional */ | |
150 | CSSM_DATA iv = {0, NULL}; | |
151 | CSSM_DATA_PTR ivPtr = NULL; | |
152 | if(blockSizeInBytes) { | |
153 | coder.allocItem(iv, blockSizeInBytes); | |
154 | ivPtr = &iv; | |
155 | } | |
156 | ||
157 | /* P12 style key derivation */ | |
158 | crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, | |
159 | keySizeInBits, iterCount, salt, pwd, passKey, iv); | |
160 | if(crtn) { | |
161 | return crtn; | |
162 | } | |
163 | /* subsequent errors to errOut: */ | |
164 | ||
165 | /* CSSM context */ | |
166 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
167 | encrAlg, | |
168 | mode, | |
169 | NULL, // access cred | |
170 | &ckey, | |
171 | ivPtr, // InitVector, optional | |
172 | padding, | |
173 | NULL, // Params | |
174 | &ccHand); | |
175 | if(crtn) { | |
176 | cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn); | |
177 | goto errOut; | |
178 | } | |
179 | ||
180 | /* go - CSP mallocs ptext and rem data */ | |
181 | CSSM_SIZE bytesDecrypted; | |
182 | crtn = CSSM_DecryptData(ccHand, | |
183 | &cipherText, | |
184 | 1, | |
185 | &ourPtext, | |
186 | 1, | |
187 | &bytesDecrypted, | |
188 | &remData); | |
189 | if(crtn) { | |
190 | cuPrintError("CSSM_DecryptData", crtn); | |
191 | } | |
192 | else { | |
193 | coder.allocCopyItem(ourPtext, plainText); | |
194 | plainText.Length = bytesDecrypted; | |
195 | ||
196 | /* plaintext copied into coder space; free the memory allocated | |
197 | * by the CSP */ | |
198 | freeCssmMemory(cspHand, ourPtext.Data); | |
199 | } | |
200 | /* an artifact of CSPFullPLuginSession - this never contains | |
201 | * valid data but sometimes gets mallocds */ | |
202 | if(remData.Data) { | |
203 | freeCssmMemory(cspHand, remData.Data); | |
204 | } | |
205 | errOut: | |
206 | if(ccHand) { | |
207 | CSSM_DeleteContext(ccHand); | |
208 | } | |
209 | CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); | |
210 | return crtn; | |
211 | } | |
212 | ||
213 | /* | |
214 | * Decrypt (typically, an encrypted P7 ContentInfo contents) | |
215 | */ | |
216 | CSSM_RETURN p12Encrypt( | |
217 | CSSM_CSP_HANDLE cspHand, | |
218 | const CSSM_DATA &plainText, | |
219 | CSSM_ALGORITHMS keyAlg, | |
220 | CSSM_ALGORITHMS encrAlg, | |
221 | CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only | |
222 | uint32 keySizeInBits, | |
223 | uint32 blockSizeInBytes, // for IV | |
224 | CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. | |
225 | CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. | |
226 | uint32 iterCount, | |
227 | const CSSM_DATA &salt, | |
228 | /* exactly one of the following two must be valid */ | |
229 | const CSSM_DATA *pwd, // unicode external representation | |
230 | const CSSM_KEY *passKey, | |
231 | SecNssCoder &coder, // for mallocing cipherText | |
232 | CSSM_DATA &cipherText) | |
233 | { | |
234 | CSSM_RETURN crtn; | |
235 | CSSM_KEY ckey; | |
236 | CSSM_CC_HANDLE ccHand = 0; | |
237 | CSSM_DATA ourCtext = {0, NULL}; | |
238 | CSSM_DATA remData = {0, NULL}; | |
239 | ||
240 | /* P12 style IV derivation, optional */ | |
241 | CSSM_DATA iv = {0, NULL}; | |
242 | CSSM_DATA_PTR ivPtr = NULL; | |
243 | if(blockSizeInBytes) { | |
244 | coder.allocItem(iv, blockSizeInBytes); | |
245 | ivPtr = &iv; | |
246 | } | |
247 | ||
248 | /* P12 style key derivation */ | |
249 | crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, | |
250 | keySizeInBits, iterCount, salt, pwd, passKey, iv); | |
251 | if(crtn) { | |
252 | return crtn; | |
253 | } | |
254 | /* subsequent errors to errOut: */ | |
255 | ||
256 | /* CSSM context */ | |
257 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
258 | encrAlg, | |
259 | mode, | |
260 | NULL, // access cred | |
261 | &ckey, | |
262 | ivPtr, // InitVector, optional | |
263 | padding, | |
264 | NULL, // Params | |
265 | &ccHand); | |
266 | if(crtn) { | |
267 | cuPrintError("CSSM_CSP_CreateSymmetricContext", crtn); | |
268 | goto errOut; | |
269 | } | |
270 | ||
271 | /* go - CSP mallocs ctext and rem data */ | |
272 | CSSM_SIZE bytesEncrypted; | |
273 | crtn = CSSM_EncryptData(ccHand, | |
274 | &plainText, | |
275 | 1, | |
276 | &ourCtext, | |
277 | 1, | |
278 | &bytesEncrypted, | |
279 | &remData); | |
280 | if(crtn) { | |
281 | cuPrintError("CSSM_DecryptData", crtn); | |
282 | } | |
283 | else { | |
284 | coder.allocCopyItem(ourCtext, cipherText); | |
285 | cipherText.Length = bytesEncrypted; | |
286 | ||
287 | /* plaintext copied into coder space; free the memory allocated | |
288 | * by the CSP */ | |
289 | freeCssmMemory(cspHand, ourCtext.Data); | |
290 | } | |
291 | /* an artifact of CSPFUllPLuginSession - this never contains | |
292 | * valid data but sometimes gets mallocds */ | |
293 | if(remData.Data) { | |
294 | freeCssmMemory(cspHand, remData.Data); | |
295 | } | |
296 | errOut: | |
297 | if(ccHand) { | |
298 | CSSM_DeleteContext(ccHand); | |
299 | } | |
300 | CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); | |
301 | return crtn; | |
302 | } | |
303 | ||
304 | /* | |
305 | * Calculate the MAC for a PFX. Caller is either going compare | |
306 | * the result against an existing PFX's MAC or drop the result into | |
307 | * a newly created PFX. | |
308 | */ | |
309 | CSSM_RETURN p12GenMac( | |
310 | CSSM_CSP_HANDLE cspHand, | |
311 | const CSSM_DATA &ptext, // e.g., NSS_P12_DecodedPFX.derAuthSaafe | |
312 | CSSM_ALGORITHMS alg, // better be SHA1! | |
313 | unsigned iterCount, | |
314 | const CSSM_DATA &salt, | |
315 | /* exactly one of the following two must be valid */ | |
316 | const CSSM_DATA *pwd, // unicode external representation | |
317 | const CSSM_KEY *passKey, | |
318 | SecNssCoder &coder, // for mallocing macData | |
319 | CSSM_DATA &macData) // RETURNED | |
320 | { | |
321 | CSSM_RETURN crtn; | |
322 | CSSM_CC_HANDLE ccHand = 0; | |
323 | ||
324 | /* P12 style key derivation */ | |
325 | unsigned keySizeInBits; | |
326 | CSSM_ALGORITHMS hmacAlg; | |
327 | switch(alg) { | |
328 | case CSSM_ALGID_SHA1: | |
329 | keySizeInBits = 160; | |
330 | hmacAlg = CSSM_ALGID_SHA1HMAC; | |
331 | break; | |
332 | case CSSM_ALGID_MD5: | |
333 | /* not even sure if this is legal in p12 world... */ | |
334 | keySizeInBits = 128; | |
335 | hmacAlg = CSSM_ALGID_MD5HMAC; | |
336 | break; | |
337 | default: | |
338 | return CSSMERR_CSP_INVALID_ALGORITHM; | |
339 | } | |
340 | CSSM_KEY macKey; | |
341 | CSSM_DATA iv = {0, NULL}; | |
342 | crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg, | |
343 | keySizeInBits, iterCount, salt, pwd, passKey, iv); | |
344 | if(crtn) { | |
345 | return crtn; | |
346 | } | |
347 | /* subsequent errors to errOut: */ | |
348 | ||
349 | /* prealloc the mac data */ | |
350 | coder.allocItem(macData, keySizeInBits / 8); | |
351 | crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand); | |
352 | if(crtn) { | |
353 | cuPrintError("CSSM_CSP_CreateMacContext", crtn); | |
354 | goto errOut; | |
355 | } | |
356 | ||
357 | crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData); | |
358 | if(crtn) { | |
359 | cuPrintError("CSSM_GenerateMac", crtn); | |
360 | } | |
361 | errOut: | |
362 | if(ccHand) { | |
363 | CSSM_DeleteContext(ccHand); | |
364 | } | |
365 | CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE); | |
366 | return crtn; | |
367 | } | |
368 | ||
369 | /* | |
370 | * Unwrap a shrouded key. | |
371 | */ | |
372 | CSSM_RETURN p12UnwrapKey( | |
373 | CSSM_CSP_HANDLE cspHand, | |
374 | CSSM_DL_DB_HANDLE_PTR dlDbHand, // optional | |
375 | int keyIsPermanent, // nonzero - store in DB | |
376 | const CSSM_DATA &shroudedKeyBits, | |
377 | CSSM_ALGORITHMS keyAlg, // of the unwrapping key | |
378 | CSSM_ALGORITHMS encrAlg, | |
379 | CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only | |
380 | uint32 keySizeInBits, | |
381 | uint32 blockSizeInBytes, // for IV | |
382 | CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. | |
383 | CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. | |
384 | uint32 iterCount, | |
385 | const CSSM_DATA &salt, | |
386 | const CSSM_DATA *pwd, // unicode external representation | |
387 | const CSSM_KEY *passKey, | |
388 | SecNssCoder &coder, // for mallocing privKey | |
389 | const CSSM_DATA &labelData, | |
390 | SecAccessRef access, // optional | |
391 | bool noAcl, | |
392 | CSSM_KEYUSE keyUsage, | |
393 | CSSM_KEYATTR_FLAGS keyAttrs, | |
394 | ||
395 | /* | |
396 | * Result: a private key, reference format, optionaly stored | |
397 | * in dlDbHand | |
398 | */ | |
399 | CSSM_KEY_PTR &privKey) | |
400 | { | |
401 | CSSM_RETURN crtn; | |
402 | CSSM_KEY ckey; | |
403 | CSSM_CC_HANDLE ccHand = 0; | |
404 | CSSM_KEY wrappedKey; | |
405 | CSSM_KEY unwrappedKey; | |
406 | CSSM_KEYHEADER &hdr = wrappedKey.KeyHeader; | |
407 | CSSM_DATA descrData = {0, NULL}; // not used for PKCS8 wrap | |
408 | CSSM_KEYATTR_FLAGS reqAttr = keyAttrs; | |
409 | ||
410 | ResourceControlContext rcc; | |
411 | ResourceControlContext *rccPtr = NULL; | |
412 | Security::KeychainCore::Access::Maker maker; | |
413 | ||
414 | /* P12 style IV derivation, optional */ | |
415 | CSSM_DATA iv = {0, NULL}; | |
416 | CSSM_DATA_PTR ivPtr = NULL; | |
417 | if(blockSizeInBytes) { | |
418 | coder.allocItem(iv, blockSizeInBytes); | |
419 | ivPtr = &iv; | |
420 | } | |
421 | ||
422 | /* P12 style key derivation */ | |
423 | crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, | |
424 | keySizeInBits, iterCount, salt, pwd, passKey, iv); | |
425 | if(crtn) { | |
426 | return crtn; | |
427 | } | |
428 | /* subsequent errors to errOut: */ | |
429 | ||
430 | /* CSSM context */ | |
431 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
432 | encrAlg, | |
433 | mode, | |
434 | NULL, // access cred | |
435 | &ckey, | |
436 | ivPtr, // InitVector, optional | |
437 | padding, | |
438 | NULL, // Params | |
439 | &ccHand); | |
440 | if(crtn) { | |
441 | p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); | |
442 | goto errOut; | |
443 | } | |
444 | if(dlDbHand) { | |
445 | crtn = p12AddContextAttribute(ccHand, | |
446 | CSSM_ATTRIBUTE_DL_DB_HANDLE, | |
447 | sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE), | |
448 | dlDbHand); | |
449 | if(crtn) { | |
450 | p12LogCssmError("AddContextAttribute", crtn); | |
451 | goto errOut; | |
452 | } | |
453 | } | |
454 | ||
455 | /* | |
456 | * Cook up minimal WrappedKey header fields | |
457 | */ | |
458 | memset(&wrappedKey, 0, sizeof(CSSM_KEY)); | |
459 | memset(&unwrappedKey, 0, sizeof(CSSM_KEY)); | |
460 | ||
461 | hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; | |
462 | hdr.BlobType = CSSM_KEYBLOB_WRAPPED; | |
463 | hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; | |
464 | ||
465 | /* | |
466 | * This one we do not know. The CSP will figure out the format | |
467 | * of the unwrapped key after it decrypts the raw key material. | |
468 | */ | |
469 | hdr.AlgorithmId = CSSM_ALGID_NONE; | |
470 | hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; | |
471 | ||
472 | /* also inferred by CSP */ | |
473 | hdr.LogicalKeySizeInBits = 0; | |
474 | hdr.KeyAttr = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE; | |
475 | hdr.KeyUsage = CSSM_KEYUSE_ANY; | |
476 | hdr.WrapAlgorithmId = encrAlg; | |
477 | hdr.WrapMode = mode; | |
478 | ||
479 | if(dlDbHand && keyIsPermanent) { | |
480 | reqAttr |= CSSM_KEYATTR_PERMANENT; | |
481 | } | |
482 | ||
483 | wrappedKey.KeyData = shroudedKeyBits; | |
484 | ||
485 | if(!noAcl) { | |
486 | // Create a Access::Maker for the initial owner of the private key. | |
487 | memset(&rcc, 0, sizeof(rcc)); | |
488 | maker.initialOwner(rcc); | |
489 | rccPtr = &rcc; | |
490 | } | |
491 | ||
492 | crtn = CSSM_UnwrapKey(ccHand, | |
493 | NULL, // PublicKey | |
494 | &wrappedKey, | |
495 | keyUsage, | |
496 | reqAttr, | |
497 | &labelData, | |
498 | rccPtr, // CredAndAclEntry | |
499 | privKey, | |
500 | &descrData); // required | |
501 | if(crtn) { | |
502 | p12LogCssmError("CSSM_UnwrapKey", crtn); | |
503 | if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) { | |
504 | /* report in a keychain-friendly way */ | |
505 | crtn = errSecDuplicateItem; | |
506 | } | |
507 | } | |
508 | ||
509 | // Finally fix the acl and owner of the private key to the | |
510 | // specified access control settings. | |
511 | if((crtn == CSSM_OK) && !noAcl) { | |
512 | try { | |
513 | CssmClient::KeyAclBearer bearer( | |
514 | cspHand, *privKey, Allocator::standard()); | |
515 | SecPointer<KeychainCore::Access> initialAccess(access ? | |
516 | KeychainCore::Access::required(access) : /* caller-supplied */ | |
517 | new KeychainCore::Access("privateKey")); /* default */ | |
518 | initialAccess->setAccess(bearer, maker); | |
519 | } | |
520 | catch (const CssmError &e) { | |
521 | /* not implemented means we're talking to the CSP which does | |
522 | * not implement ACLs */ | |
523 | if(e.error != CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED) { | |
524 | crtn = e.error; | |
525 | } | |
526 | } | |
527 | catch(...) { | |
528 | p12ErrorLog("p12 exception on setAccess\n"); | |
529 | crtn = errSecAuthFailed; /* ??? */ | |
530 | } | |
531 | } | |
532 | ||
533 | errOut: | |
534 | if(ccHand) { | |
535 | CSSM_DeleteContext(ccHand); | |
536 | } | |
537 | CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); | |
538 | return crtn; | |
539 | } | |
540 | ||
541 | /* | |
542 | * Wrap a private key, yielding shrouded key bits. | |
543 | */ | |
544 | CSSM_RETURN p12WrapKey( | |
545 | CSSM_CSP_HANDLE cspHand, | |
546 | CSSM_KEY_PTR privKey, | |
547 | const CSSM_ACCESS_CREDENTIALS *privKeyCreds, | |
548 | CSSM_ALGORITHMS keyAlg, // of the unwrapping key | |
549 | CSSM_ALGORITHMS encrAlg, | |
550 | CSSM_ALGORITHMS pbeHashAlg, // SHA1, MD5 only | |
551 | uint32 keySizeInBits, | |
552 | uint32 blockSizeInBytes, // for IV | |
553 | CSSM_PADDING padding, // CSSM_PADDING_PKCS7, etc. | |
554 | CSSM_ENCRYPT_MODE mode, // CSSM_ALGMODE_CBCPadIV8, etc. | |
555 | uint32 iterCount, | |
556 | const CSSM_DATA &salt, | |
557 | const CSSM_DATA *pwd, // unicode external representation | |
558 | const CSSM_KEY *passKey, | |
559 | SecNssCoder &coder, // for mallocing keyBits | |
560 | CSSM_DATA &shroudedKeyBits) // RETURNED | |
561 | { | |
562 | CSSM_RETURN crtn; | |
563 | CSSM_KEY ckey; | |
564 | CSSM_CC_HANDLE ccHand = 0; | |
565 | CSSM_KEY wrappedKey; | |
566 | CSSM_CONTEXT_ATTRIBUTE attr; | |
567 | CSSM_DATA descrData = {0, NULL}; | |
568 | CSSM_ACCESS_CREDENTIALS creds; | |
569 | ||
570 | /* key must be extractable */ | |
571 | if (!(privKey->KeyHeader.KeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { | |
572 | return errSecDataNotAvailable; | |
573 | } | |
574 | ||
575 | if(privKeyCreds == NULL) { | |
576 | /* i.e., key is from the bare CSP with no ACL support */ | |
577 | memset(&creds, 0, sizeof(creds)); | |
578 | privKeyCreds = &creds; | |
579 | } | |
580 | ||
581 | /* P12 style IV derivation, optional */ | |
582 | CSSM_DATA iv = {0, NULL}; | |
583 | CSSM_DATA_PTR ivPtr = NULL; | |
584 | if(blockSizeInBytes) { | |
585 | coder.allocItem(iv, blockSizeInBytes); | |
586 | ivPtr = &iv; | |
587 | } | |
588 | ||
589 | /* P12 style key derivation */ | |
590 | crtn = p12KeyGen(cspHand, ckey, true, keyAlg, pbeHashAlg, | |
591 | keySizeInBits, iterCount, salt, pwd, passKey, iv); | |
592 | if(crtn) { | |
593 | return crtn; | |
594 | } | |
595 | /* subsequent errors to errOut: */ | |
596 | ||
597 | /* CSSM context */ | |
598 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
599 | encrAlg, | |
600 | mode, | |
601 | NULL, // access cred | |
602 | &ckey, | |
603 | ivPtr, // InitVector, optional | |
604 | padding, | |
605 | NULL, // Params | |
606 | &ccHand); | |
607 | if(crtn) { | |
608 | p12LogCssmError("CSSM_CSP_CreateSymmetricContext", crtn); | |
609 | goto errOut; | |
610 | } | |
611 | ||
612 | memset(&wrappedKey, 0, sizeof(CSSM_KEY)); | |
613 | ||
614 | /* specify PKCS8 wrap format */ | |
615 | attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT; | |
616 | attr.AttributeLength = sizeof(uint32); | |
617 | attr.Attribute.Uint32 = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; | |
618 | crtn = CSSM_UpdateContextAttributes( | |
619 | ccHand, | |
620 | 1, | |
621 | &attr); | |
622 | if(crtn) { | |
623 | p12LogCssmError("CSSM_UpdateContextAttributes", crtn); | |
624 | goto errOut; | |
625 | } | |
626 | ||
627 | crtn = CSSM_WrapKey(ccHand, | |
628 | privKeyCreds, | |
629 | privKey, | |
630 | &descrData, // DescriptiveData | |
631 | &wrappedKey); | |
632 | if(crtn) { | |
633 | p12LogCssmError("CSSM_WrapKey", crtn); | |
634 | } | |
635 | else { | |
636 | coder.allocCopyItem(wrappedKey.KeyData, shroudedKeyBits); | |
637 | ||
638 | /* this was mallocd by CSP */ | |
639 | freeCssmMemory(cspHand, wrappedKey.KeyData.Data); | |
640 | } | |
641 | errOut: | |
642 | if(ccHand) { | |
643 | CSSM_DeleteContext(ccHand); | |
644 | } | |
645 | CSSM_FreeKey(cspHand, NULL, &ckey, CSSM_FALSE); | |
646 | return crtn; | |
647 | } |