]> git.saurik.com Git - apple/security.git/blob - sec/Security/p12import.c
Security-55471.14.4.tar.gz
[apple/security.git] / sec / Security / p12import.c
1 /*
2 * Copyright (c) 2007-2010 Apple 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 #include <libDER/oids.h>
25 #include <security_asn1/nssUtils.h>
26 #include <security_asn1/SecAsn1Templates.h>
27 #include <security_asn1/pkcs12Templates.h>
28
29 #include <CommonCrypto/CommonCryptor.h>
30 #include <CommonCrypto/CommonDigest.h>
31 #include <CommonCrypto/CommonHMAC.h>
32
33 #include <CoreFoundation/CoreFoundation.h>
34
35 #include <AssertMacros.h>
36 #include <Security/SecInternal.h>
37 #include <utilities/debugging.h>
38
39 #include "p12pbegen.h"
40 #include "p12import.h"
41 #include "SecImportExport.h"
42
43 #ifdef NDEBUG
44 #define p12DecodeLog(args...)
45 #else
46 #define p12DecodeLog(args...) secdebug("pkcs12", "%s\n", args)
47 #endif
48
49 int decode_item(pkcs12_context * context, const SecAsn1Item *item,
50 const SecAsn1Template *tmpl, void *dest);
51 inline int decode_item(pkcs12_context * context, const SecAsn1Item *item,
52 const SecAsn1Template *tmpl, void *dest)
53 {
54 return SecAsn1Decode(context->coder, (const char *)item->Data, item->Length, tmpl, dest);
55 }
56
57 void alloc_item(pkcs12_context * context, SecAsn1Item *item, size_t len);
58 inline void alloc_item(pkcs12_context * context, SecAsn1Item *item, size_t len)
59 {
60 SecAsn1AllocItem(context->coder, item, len);
61 }
62
63 /*
64 * OIDS for P12 map to the following attributes.
65 */
66 typedef struct {
67 CCAlgorithm alg;
68 uint32_t keySizeInBits; // XXX/cs make keysize in bytes
69 uint32_t blockSizeInBytes; // for IV, optional, make iv size in bytes
70 CCOptions options; // padding and mode.
71 } PKCSOidInfo;
72
73 /* PKCS12 algorithms OID_ISO_MEMBER, OID_US, OID_RSA, OID_PKCS, OID_PKCS_12 */
74 static const uint8_t PKCS12_pbep[] = { 42, 134, 72, 134, 247, 13, 1, 12, 1 };
75 static const DERItem OID_PKCS12_pbep = { (uint8_t*)PKCS12_pbep, sizeof(PKCS12_pbep) };
76 static const PKCSOidInfo pkcsOidInfos[] = {
77 { /*CSSMOID_PKCS12_pbeWithSHAAnd128BitRC4,*/
78 kCCAlgorithmRC4, 128, 0/* stream cipher */, 0 },
79 { /*CSSMOID_PKCS12_pbeWithSHAAnd40BitRC4,*/
80 kCCAlgorithmRC4, 40, 0/* stream cipher */, 0 },
81 { /*CSSMOID_PKCS12_pbeWithSHAAnd3Key3DESCBC,*/
82 kCCAlgorithm3DES, 64 * 3, 8, kCCOptionPKCS7Padding },
83 { /*CSSMOID_PKCS12_pbeWithSHAAnd2Key3DESCBC,*/
84 -1 /*CSSM_ALGID_3DES_2KEY unsupported*/, 64 * 2, 8, kCCOptionPKCS7Padding },
85 { /*CSSMOID_PKCS12_pbeWithSHAAnd128BitRC2CBC,*/
86 kCCAlgorithmRC2, 128, 8, kCCOptionPKCS7Padding },
87 { /*CSSMOID_PKCS12_pbewithSHAAnd40BitRC2CBC,*/
88 kCCAlgorithmRC2, 40, 8, kCCOptionPKCS7Padding }
89 };
90
91 #define NUM_PKCS_OID_INFOS (sizeof(pkcsOidInfos) / sizeof(pkcsOidInfos[1]))
92
93 static int pkcsOidToParams(const SecAsn1Item *oid, CCAlgorithm *alg,
94 uint32_t *keySizeInBits, uint32_t *blockSizeInBytes, CCOptions *options)
95 {
96 DERItem prefix = { oid->Data, oid->Length };
97 prefix.length -= 1;
98 if (DEROidCompare(&OID_PKCS12_pbep, &prefix)) {
99 uint8_t postfix = oid->Data[oid->Length-1];
100 if (postfix > NUM_PKCS_OID_INFOS || postfix == 4)
101 return -1;
102 *alg = pkcsOidInfos[postfix-1].alg;
103 *keySizeInBits = pkcsOidInfos[postfix-1].keySizeInBits;
104 *blockSizeInBytes = pkcsOidInfos[postfix-1].blockSizeInBytes;
105 *options = pkcsOidInfos[postfix-1].options;
106 return 0;
107 }
108 return -1;
109 }
110
111 static int p12DataToInt(const SecAsn1Item *cdata, uint32_t *u)
112 {
113 /* default/not present */
114 if((cdata->Length == 0) || (cdata->Data == NULL)) {
115 *u = 0;
116 return 0;
117 }
118 size_t len = cdata->Length;
119 if(len > sizeof(uint32_t)) {
120 return -1;
121 }
122
123 uint32_t rtn = 0;
124 uint8_t *cp = cdata->Data;
125 size_t i;
126 for(i = 0; i < len; i++) {
127 rtn = (rtn << 8) | *cp++;
128 }
129 *u = rtn;
130 return 0;
131 }
132
133 /*
134 * Parse an SecAsn1AlgId specific to P12.
135 * Decode the alg params as a NSS_P12_PBE_Params and parse and
136 * return the result if the pbeParams is non-NULL.
137 */
138 static int algIdParse(pkcs12_context * context,
139 const SecAsn1AlgId *algId, NSS_P12_PBE_Params *pbeParams/*optional*/)
140 {
141 p12DecodeLog("algIdParse");
142 const SecAsn1Item *param = &algId->parameters;
143 require(pbeParams, out);
144 require(param && param->Length, out);
145 memset(pbeParams, 0, sizeof(*pbeParams));
146 require_noerr(decode_item(context, param, NSS_P12_PBE_ParamsTemplate, pbeParams), out);
147
148 return 0;
149 out:
150 return -1;
151 }
152
153 static int p12Decrypt(pkcs12_context * context, const SecAsn1AlgId *algId,
154 const SecAsn1Item *cipherText, SecAsn1Item *plainText)
155 {
156 NSS_P12_PBE_Params pbep;
157 // XXX/cs not requiring decoding, but if pbep is uninit this will fail later
158 algIdParse(context, algId, &pbep);
159
160 CCAlgorithm alg = 0;
161 uint32_t keySizeInBits = 0;
162 uint32_t blockSizeInBytes = 0; // for IV, optional
163 CCOptions options = 0;
164 require_noerr_quiet(pkcsOidToParams(&algId->algorithm, &alg, &keySizeInBits,
165 &blockSizeInBytes, &options), out);
166
167 uint32_t iterCount = 0;
168 require_noerr(p12DataToInt(&pbep.iterations, &iterCount), out);
169
170 /* P12 style key derivation */
171 SecAsn1Item key = {0, NULL};
172 if(keySizeInBits)
173 alloc_item(context, &key, (keySizeInBits+7)/8);
174 require_noerr(p12_pbe_gen(context->passphrase, pbep.salt.Data, pbep.salt.Length,
175 iterCount, PBE_ID_Key, key.Data, key.Length), out);
176
177 /* P12 style IV derivation, optional */
178 SecAsn1Item iv = {0, NULL};
179 if(blockSizeInBytes) {
180 alloc_item(context, &iv, blockSizeInBytes);
181 require_noerr(p12_pbe_gen(context->passphrase, pbep.salt.Data, pbep.salt.Length,
182 iterCount, PBE_ID_IV, iv.Data, iv.Length), out);
183 }
184
185 SecAsn1Item ourPtext = {0, NULL};
186 alloc_item(context, &ourPtext, cipherText->Length);
187 require_noerr(CCCrypt(kCCDecrypt, alg, options/*kCCOptionPKCS7Padding*/,
188 key.Data, key.Length, iv.Data, cipherText->Data, cipherText->Length,
189 ourPtext.Data, ourPtext.Length, &ourPtext.Length), out);
190 *plainText = ourPtext;
191
192 return 0;
193 out:
194 return -1;
195 }
196
197 static int emit_item(pkcs12_context * context, NSS_Attribute **attrs,
198 CFStringRef item_key, CFTypeRef item_value)
199 {
200 int result = -1;
201 /* parse attrs into friendlyName, localKeyId; ignoring generic attrs */
202 CFMutableDictionaryRef attr_dict = CFDictionaryCreateMutable(kCFAllocatorDefault,
203 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
204 require(attr_dict, out);
205 unsigned numAttrs = nssArraySize((const void **)attrs);
206 unsigned int dex;
207 for(dex = 0; dex < numAttrs; dex++) {
208 NSS_Attribute *attr = attrs[dex];
209 unsigned numValues = nssArraySize((const void**)attr->attrValue);
210 DERItem type = { attr->attrType.Data, attr->attrType.Length };
211 if(DEROidCompare(&type, &oidFriendlyName)) {
212 /*
213 * BMP string (UniCode). Spec says only one legal value.
214 */
215 require(numValues == 1, out);
216 SecAsn1Item friendly_name_asn1;
217 require_noerr(decode_item(context, attr->attrValue[0],
218 kSecAsn1BMPStringTemplate, &friendly_name_asn1), out);
219 CFStringRef friendly_name = CFStringCreateWithBytes(kCFAllocatorDefault,
220 friendly_name_asn1.Data, friendly_name_asn1.Length,
221 kCFStringEncodingUnicode, true);
222 if (friendly_name) {
223 CFDictionarySetValue(attr_dict, kSecImportItemLabel, friendly_name);
224 CFRelease(friendly_name);
225 }
226 }
227 else if(DEROidCompare(&type, &oidLocalKeyId)) {
228 /*
229 * Octet string. Spec says only one legal value.
230 */
231 require(numValues == 1, out);
232 SecAsn1Item local_key_id;
233 require_noerr(decode_item(context, attr->attrValue[0],
234 kSecAsn1OctetStringTemplate, &local_key_id), out);
235 CFDataRef keyid = CFDataCreate(kCFAllocatorDefault, local_key_id.Data, local_key_id.Length);
236 if (keyid) {
237 CFDictionarySetValue(attr_dict, kSecImportItemKeyID, keyid);
238 CFRelease(keyid);
239 }
240 }
241 }
242
243 CFTypeRef key = CFDictionaryGetValue(attr_dict, kSecImportItemKeyID);
244 if (!key)
245 key = CFDictionaryGetValue(attr_dict, kSecImportItemLabel);
246 if (!key)
247 key = item_value;
248
249 CFMutableDictionaryRef item = (CFMutableDictionaryRef)CFDictionaryGetValue(context->items, key);
250 if (item) {
251 CFDictionarySetValue(item, item_key, item_value);
252 } else {
253 CFDictionarySetValue(attr_dict, item_key, item_value);
254 CFDictionarySetValue(context->items, key, attr_dict);
255 }
256 result = 0;
257 out:
258 CFReleaseSafe(attr_dict);
259 return result;
260 }
261
262
263 /*
264 * ShroudedKeyBag parser w/decrypt
265 */
266 static int shroudedKeyBagParse(pkcs12_context * context, const NSS_P12_SafeBag *safeBag)
267 {
268 p12DecodeLog("Found shrouded key bag");
269
270 const NSS_P12_ShroudedKeyBag *keyBag = safeBag->bagValue.shroudedKeyBag;
271 SecAsn1Item ptext = {0, NULL};
272 require_noerr_quiet(p12Decrypt(context, &keyBag->algorithm,
273 &keyBag->encryptedData, &ptext), out);
274
275 /* Decode PKCS#8 formatted private key */
276 NSS_PrivateKeyInfo pki;
277 memset(&pki, 0, sizeof(pki));
278 require_noerr(decode_item(context, &ptext, kSecAsn1PrivateKeyInfoTemplate,
279 &pki), out);
280
281 DERItem algorithm = { pki.algorithm.algorithm.Data, pki.algorithm.algorithm.Length };
282 CFDataRef algoidData = NULL;
283 if (DEROidCompare(&oidEcPubKey, &algorithm)) {
284 algoidData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, oidEcPubKey.data, oidEcPubKey.length, kCFAllocatorNull);
285 } else if (DEROidCompare(&oidRsa, &algorithm)) {
286 algoidData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, oidRsa.data, oidRsa.length, kCFAllocatorNull);
287 } else {
288 goto out;
289 }
290 require_noerr(emit_item(context, safeBag->bagAttrs, CFSTR("algid"), algoidData), out);
291 CFRelease(algoidData);
292
293 CFDataRef keyData = CFDataCreate(kCFAllocatorDefault, pki.privateKey.Data, pki.privateKey.Length);
294 require_noerr(emit_item(context, safeBag->bagAttrs, CFSTR("key"), keyData), out);
295 CFRelease(keyData);
296
297 return 0;
298 out:
299 return -1;
300 }
301
302
303 /*
304 * CertBag parser
305 */
306 static int certBagParse(pkcs12_context * context, const NSS_P12_SafeBag *safeBag)
307 {
308 p12DecodeLog("found certBag");
309 NSS_P12_CertBag *certBag = safeBag->bagValue.certBag;
310
311 switch(certBag->type) {
312 case CT_X509:
313 {
314 /* certType = CSSM_CERT_X_509v3;
315 certEncoding = CSSM_CERT_ENCODING_DER; */
316 CFDataRef certData = CFDataCreate(kCFAllocatorDefault, certBag->certValue.Data,
317 certBag->certValue.Length);
318 require_noerr(emit_item(context, safeBag->bagAttrs, CFSTR("cert"), certData), out);
319 CFRelease(certData);
320 break;
321 }
322 case CT_SDSI:
323 /* certType = CSSM_CERT_SDSIv1; */
324 /* it's base64 encoded - no value for that in this enum */
325 break;
326 default:
327 return -1;
328 }
329 return 0;
330 out:
331 return -1;
332 }
333
334
335 /*
336 * Parse an encoded NSS_P12_SafeContents. This could be either
337 * present as plaintext in an AuthSafe or decrypted.
338 */
339 static int safeContentsParse(pkcs12_context * context, const SecAsn1Item *contentsBlob)
340 {
341 p12DecodeLog("safeContentsParse");
342
343 NSS_P12_SafeContents sc;
344 memset(&sc, 0, sizeof(sc));
345 require_noerr(decode_item(context, contentsBlob, NSS_P12_SafeContentsTemplate,
346 &sc), out);
347
348 unsigned numBags = nssArraySize((const void **)sc.bags);
349 unsigned int dex;
350 for(dex=0; dex<numBags; dex++) {
351 NSS_P12_SafeBag *bag = sc.bags[dex];
352 assert(bag != NULL);
353
354 /* ensure that *something* is there */
355 require(bag->bagValue.keyBag != NULL, out);
356
357 /*
358 * Break out to individual bag type
359 */
360 switch(bag->type) {
361 case BT_ShroudedKeyBag:
362 require_noerr(shroudedKeyBagParse(context, bag), out);
363 break;
364 case BT_CertBag:
365 require_noerr(certBagParse(context, bag), out);
366 break;
367
368 case BT_KeyBag:
369 /* keyBagParse(bag); */
370 p12DecodeLog("Unhandled BT_KeyBag");
371 break;
372 case BT_CrlBag:
373 /* crlBagParse(bag); */
374 p12DecodeLog("Unhandled BT_CrlBag");
375 break;
376 case BT_SecretBag:
377 /* secretBagParse(bag); */
378 p12DecodeLog("Unhandled BT_SecretBag");
379 break;
380 case BT_SafeContentsBag:
381 /* safeContentsBagParse(bag); */
382 p12DecodeLog("Unhandled BT_SafeContentsBag");
383 break;
384 default:
385 p12DecodeLog("Unknown bag type");
386 goto out;
387 break;
388 }
389 }
390 return 0;
391 out:
392 return -1;
393 }
394
395 /*
396 * Parse a ContentInfo in the context of (i.e., as an element of)
397 * an AuthenticatedSafe.
398 */
399 static int authSafeElementParse(pkcs12_context * context, const NSS_P7_DecodedContentInfo *info)
400 {
401 p12DecodeLog("authSafeElementParse");
402 switch(info->type) {
403 case CT_Data:
404 /* unencrypted SafeContents */
405 require_noerr(safeContentsParse(context, info->content.data), out);
406 break;
407
408 case CT_EncryptedData:
409 {
410 /*
411 * Decrypt contents to get a SafeContents and
412 * then parse that.
413 */
414 SecAsn1Item ptext = {0, NULL};
415 NSS_P7_EncryptedData *edata = info->content.encryptData;
416 require_noerr_quiet(p12Decrypt(context, &edata->contentInfo.encrAlg,
417 &edata->contentInfo.encrContent, &ptext), out);
418 require_noerr(safeContentsParse(context, &ptext), out);
419 break;
420 }
421 default:
422 break;
423 }
424 return 0;
425 out:
426 return -1;
427 }
428
429 /*
430 * Parse an encoded NSS_P12_AuthenticatedSafe
431 */
432 static int authSafeParse(pkcs12_context * context, const SecAsn1Item *authSafeBlob)
433 {
434 p12DecodeLog("authSafeParse");
435 NSS_P12_AuthenticatedSafe authSafe;
436 memset(&authSafe, 0, sizeof(authSafe));
437 require_noerr(decode_item(context, authSafeBlob,
438 NSS_P12_AuthenticatedSafeTemplate, &authSafe), out);
439
440 unsigned numInfos = nssArraySize((const void **)authSafe.info);
441 unsigned int dex;
442 for (dex=0; dex<numInfos; dex++) {
443 NSS_P7_DecodedContentInfo *info = authSafe.info[dex];
444 require_noerr_quiet(authSafeElementParse(context, info), out);
445 }
446 return 0;
447 out:
448 return -1;
449 }
450
451 static int p12VerifyMac(pkcs12_context * context, const NSS_P12_DecodedPFX *pfx)
452 {
453 NSS_P12_MacData *macData = pfx->macData;
454 require(macData, out);
455 NSS_P7_DigestInfo *digestInfo = &macData->mac;
456 require(digestInfo, out);
457 SecAsn1Item *algOid = &digestInfo->digestAlgorithm.algorithm;
458 require(algOid, out);
459
460 /* has to be OID_OIW_SHA1 */
461 DERItem algOidItem = { algOid->Data, algOid->Length };
462 require(algOidItem.length && DEROidCompare(&oidSha1, &algOidItem), out);
463
464 uint32_t iterCount = 0;
465 require_noerr_quiet(p12DataToInt(&macData->iterations, &iterCount), out);
466 if (iterCount == 0) { /* optional, default 1 */
467 iterCount = 1;
468 }
469
470 /*
471 * In classic fashion, the PKCS12 spec now says:
472 *
473 * When password integrity mode is used to secure a PFX PDU,
474 * an SHA-1 HMAC is computed on the BER-encoding of the contents
475 * of the content field of the authSafe field in the PFX PDU.
476 *
477 * So here we go.
478 */
479 uint8_t hmac_key[CC_SHA1_DIGEST_LENGTH];
480 require_noerr_quiet(p12_pbe_gen(context->passphrase,
481 macData->macSalt.Data, macData->macSalt.Length,
482 iterCount, PBE_ID_MAC, hmac_key, sizeof(hmac_key)), out);
483
484 /* prealloc the mac data */
485 SecAsn1Item verifyMac;
486 alloc_item(context, &verifyMac, CC_SHA1_DIGEST_LENGTH);
487 SecAsn1Item *ptext = pfx->authSafe.content.data;
488 CCHmac(kCCHmacAlgSHA1, hmac_key, CC_SHA1_DIGEST_LENGTH,
489 ptext->Data, ptext->Length, verifyMac.Data);
490 require_quiet(nssCompareSecAsn1Items(&verifyMac, &digestInfo->digest), out);
491
492 return 0;
493 out:
494 return -1;
495 }
496
497 p12_error p12decode(pkcs12_context * context, CFDataRef cdpfx)
498 {
499 int err = p12_decodeErr;
500 NSS_P12_DecodedPFX pfx;
501 memset(&pfx, 0, sizeof(pfx));
502 SecAsn1Item raw_blob = { CFDataGetLength(cdpfx), (void*)CFDataGetBytePtr(cdpfx) };
503
504 require_noerr_quiet(decode_item(context, &raw_blob, NSS_P12_DecodedPFXTemplate, &pfx), out);
505 NSS_P7_DecodedContentInfo *dci = &pfx.authSafe;
506
507 /* only support CT_Data at top level (password based integrity mode) */
508 require(dci->type == CT_Data, out);
509 require(pfx.macData, out);
510
511 require_noerr_action_quiet(p12VerifyMac(context, &pfx), out, err = p12_passwordErr);
512 require_noerr_quiet(authSafeParse(context, dci->content.data), out);
513
514 return errSecSuccess;
515 out:
516 return err;
517 }