1/*
2 * Copyright (c) 2007-2010,2012-2014 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
49int decode_item(pkcs12_context * context, const SecAsn1Item *item,
50    const SecAsn1Template *tmpl, void *dest);
51inline 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
57void alloc_item(pkcs12_context * context, SecAsn1Item *item, size_t len);
58inline 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 */
66typedef 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 */
74static const uint8_t PKCS12_pbep[] = { 42, 134, 72, 134, 247, 13, 1, 12, 1 };
75static const DERItem OID_PKCS12_pbep = { (uint8_t*)PKCS12_pbep, sizeof(PKCS12_pbep)  };
76static 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
93static 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
111static 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 */
138static 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;
149out:
150    return -1;
151}
152
153static 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;
193out:
194    return -1;
195}
196
197static 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;
257out:
258    CFReleaseSafe(attr_dict);
259    return result;
260}
261
262
263/*
264 * ShroudedKeyBag parser w/decrypt
265 */
266static int shroudedKeyBagParse(pkcs12_context * context, const NSS_P12_SafeBag *safeBag)
267{
268    CFDataRef algoidData = NULL;
269    CFDataRef keyData = NULL;
270
271	p12DecodeLog("Found shrouded key bag");
272
273	const NSS_P12_ShroudedKeyBag *keyBag = safeBag->bagValue.shroudedKeyBag;
274    SecAsn1Item ptext = {0, NULL};
275    require_noerr_quiet(p12Decrypt(context, &keyBag->algorithm,
276        &keyBag->encryptedData, &ptext), out);
277
278    /* Decode PKCS#8 formatted private key */
279    NSS_PrivateKeyInfo pki;
280    memset(&pki, 0, sizeof(pki));
281	require_noerr(decode_item(context, &ptext, kSecAsn1PrivateKeyInfoTemplate,
282			&pki), out);
283
284    DERItem algorithm = { pki.algorithm.algorithm.Data, pki.algorithm.algorithm.Length };
285    algoidData = NULL;
286    if (DEROidCompare(&oidEcPubKey, &algorithm)) {
287        algoidData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, oidEcPubKey.data, oidEcPubKey.length, kCFAllocatorNull);
288    } else if (DEROidCompare(&oidRsa, &algorithm)) {
289        algoidData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, oidRsa.data, oidRsa.length, kCFAllocatorNull);
290    } else {
291        goto out;
292    }
293    require_noerr(emit_item(context, safeBag->bagAttrs, CFSTR("algid"), algoidData), out);
294    CFReleaseNull(algoidData);
295
296    keyData = CFDataCreate(kCFAllocatorDefault, pki.privateKey.Data, pki.privateKey.Length);
297    require_noerr(emit_item(context, safeBag->bagAttrs, CFSTR("key"), keyData), out);
298    CFReleaseNull(keyData);
299
300    return 0;
301out:
302    CFReleaseSafe(algoidData);
303    CFReleaseSafe(keyData);
304    return -1;
305}
306
307
308/*
309 * CertBag parser
310 */
311static int certBagParse(pkcs12_context * context, const NSS_P12_SafeBag *safeBag)
312{
313    CFDataRef certData = NULL;
314	p12DecodeLog("found certBag");
315	NSS_P12_CertBag *certBag = safeBag->bagValue.certBag;
316
317	switch(certBag->type) {
318		case CT_X509:
319        {
320            /* certType = CSSM_CERT_X_509v3;
321			   certEncoding = CSSM_CERT_ENCODING_DER; */
322            certData = CFDataCreate(kCFAllocatorDefault, certBag->certValue.Data,
323                certBag->certValue.Length);
324            require_noerr(emit_item(context, safeBag->bagAttrs, CFSTR("cert"), certData), out);
325            CFRelease(certData);
326            break;
327        }
328		case CT_SDSI:
329            /* certType = CSSM_CERT_SDSIv1; */
330			/* it's base64 encoded - no value for that in this enum */
331			break;
332		default:
333            return -1;
334	}
335    return 0;
336out:
337    CFReleaseSafe(certData);
338    return -1;
339}
340
341
342/*
343 * Parse an encoded NSS_P12_SafeContents. This could be either
344 * present as plaintext in an AuthSafe or decrypted.
345 */
346static int safeContentsParse(pkcs12_context * context, const SecAsn1Item *contentsBlob)
347{
348	p12DecodeLog("safeContentsParse");
349
350	NSS_P12_SafeContents sc;
351	memset(&sc, 0, sizeof(sc));
352	require_noerr(decode_item(context, contentsBlob, NSS_P12_SafeContentsTemplate,
353			&sc), out);
354
355	unsigned numBags = nssArraySize((const void **)sc.bags);
356    unsigned int dex;
357	for(dex=0; dex<numBags; dex++) {
358		NSS_P12_SafeBag *bag = sc.bags[dex];
359		assert(bag != NULL);
360
361		/* ensure that *something* is there */
362		require(bag->bagValue.keyBag != NULL, out);
363
364		/*
365		 * Break out to individual bag type
366		 */
367		switch(bag->type) {
368			case BT_ShroudedKeyBag:
369				require_noerr(shroudedKeyBagParse(context, bag), out);
370				break;
371			case BT_CertBag:
372				require_noerr(certBagParse(context, bag), out);
373				break;
374
375			case BT_KeyBag:
376				/* keyBagParse(bag); */
377                p12DecodeLog("Unhandled BT_KeyBag");
378				break;
379			case BT_CrlBag:
380				/* crlBagParse(bag); */
381                p12DecodeLog("Unhandled BT_CrlBag");
382				break;
383			case BT_SecretBag:
384				/* secretBagParse(bag); */
385                p12DecodeLog("Unhandled BT_SecretBag");
386				break;
387			case BT_SafeContentsBag:
388				/* safeContentsBagParse(bag); */
389                p12DecodeLog("Unhandled BT_SafeContentsBag");
390				break;
391			default:
392                p12DecodeLog("Unknown bag type");
393                goto out;
394                break;
395		}
396	}
397    return 0;
398out:
399    return -1;
400}
401
402/*
403 * Parse a ContentInfo in the context of (i.e., as an element of)
404 * an AuthenticatedSafe.
405 */
406static int authSafeElementParse(pkcs12_context * context, const NSS_P7_DecodedContentInfo *info)
407{
408	p12DecodeLog("authSafeElementParse");
409	switch(info->type) {
410		case CT_Data:
411			/* unencrypted SafeContents */
412			require_noerr(safeContentsParse(context, info->content.data), out);
413			break;
414
415		case CT_EncryptedData:
416		{
417			/*
418			 * Decrypt contents to get a SafeContents and
419			 * then parse that.
420			 */
421			SecAsn1Item ptext = {0, NULL};
422            NSS_P7_EncryptedData *edata = info->content.encryptData;
423            require_noerr_quiet(p12Decrypt(context, &edata->contentInfo.encrAlg,
424                &edata->contentInfo.encrContent, &ptext), out);
425			require_noerr(safeContentsParse(context, &ptext), out);
426			break;
427		}
428		default:
429            break;
430	}
431    return 0;
432out:
433    return -1;
434}
435
436/*
437 * Parse an encoded NSS_P12_AuthenticatedSafe
438 */
439static int authSafeParse(pkcs12_context * context, const SecAsn1Item *authSafeBlob)
440{
441    p12DecodeLog("authSafeParse");
442    NSS_P12_AuthenticatedSafe authSafe;
443    memset(&authSafe, 0, sizeof(authSafe));
444    require_noerr(decode_item(context, authSafeBlob,
445        NSS_P12_AuthenticatedSafeTemplate, &authSafe), out);
446
447    unsigned numInfos = nssArraySize((const void **)authSafe.info);
448    unsigned int dex;
449    for (dex=0; dex<numInfos; dex++) {
450        NSS_P7_DecodedContentInfo *info = authSafe.info[dex];
451        require_noerr_quiet(authSafeElementParse(context, info), out);
452    }
453    return 0;
454out:
455    return -1;
456}
457
458static int p12VerifyMac(pkcs12_context * context, const NSS_P12_DecodedPFX *pfx)
459{
460	NSS_P12_MacData *macData = pfx->macData;
461	require(macData, out);
462	NSS_P7_DigestInfo *digestInfo  = &macData->mac;
463    require(digestInfo, out);
464	SecAsn1Item *algOid = &digestInfo->digestAlgorithm.algorithm;
465    require(algOid, out);
466
467    /* has to be OID_OIW_SHA1 */
468    DERItem algOidItem = { algOid->Data, algOid->Length };
469    require(algOidItem.length && DEROidCompare(&oidSha1, &algOidItem), out);
470
471	uint32_t iterCount = 0;
472	require_noerr_quiet(p12DataToInt(&macData->iterations, &iterCount), out);
473	if (iterCount == 0) { /* optional, default 1 */
474		iterCount = 1;
475	}
476
477	/*
478	 * In classic fashion, the PKCS12 spec now says:
479	 *
480	 *      When password integrity mode is used to secure a PFX PDU,
481	 *      an SHA-1 HMAC is computed on the BER-encoding of the contents
482	 *      of the content field of the authSafe field in the PFX PDU.
483	 *
484	 * So here we go.
485	 */
486	uint8_t hmac_key[CC_SHA1_DIGEST_LENGTH];
487	require_noerr_quiet(p12_pbe_gen(context->passphrase,
488        macData->macSalt.Data, macData->macSalt.Length,
489        iterCount, PBE_ID_MAC, hmac_key, sizeof(hmac_key)), out);
490
491	/* prealloc the mac data */
492	SecAsn1Item verifyMac;
493	alloc_item(context, &verifyMac, CC_SHA1_DIGEST_LENGTH);
494	SecAsn1Item *ptext = pfx->authSafe.content.data;
495	CCHmac(kCCHmacAlgSHA1, hmac_key, CC_SHA1_DIGEST_LENGTH,
496        ptext->Data, ptext->Length, verifyMac.Data);
497	require_quiet(nssCompareSecAsn1Items(&verifyMac, &digestInfo->digest), out);
498
499	return 0;
500out:
501    return -1;
502}
503
504p12_error p12decode(pkcs12_context * context, CFDataRef cdpfx)
505{
506    int err = p12_decodeErr;
507	NSS_P12_DecodedPFX pfx;
508	memset(&pfx, 0, sizeof(pfx));
509    SecAsn1Item raw_blob = { CFDataGetLength(cdpfx), (void*)CFDataGetBytePtr(cdpfx) };
510
511    require_noerr_quiet(decode_item(context, &raw_blob, NSS_P12_DecodedPFXTemplate, &pfx), out);
512	NSS_P7_DecodedContentInfo *dci = &pfx.authSafe;
513
514    /* only support CT_Data at top level (password based integrity mode) */
515	require(dci->type == CT_Data, out);
516	require(pfx.macData, out);
517
518	require_noerr_action_quiet(p12VerifyMac(context, &pfx), out, err = p12_passwordErr);
519    require_noerr_quiet(authSafeParse(context, dci->content.data), out);
520
521	return errSecSuccess;
522out:
523    return err;
524}
525