/ OSX / sec / Security / p12import.c
p12import.c
  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 <Security/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      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;
301  out:
302      CFReleaseSafe(algoidData);
303      CFReleaseSafe(keyData);
304      return -1;
305  }
306  
307  
308  /*
309   * CertBag parser
310   */
311  static 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;
336  out:
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   */
346  static 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;
398  out:
399      return -1;
400  }
401  
402  /*
403   * Parse a ContentInfo in the context of (i.e., as an element of)
404   * an AuthenticatedSafe.
405   */
406  static 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;
432  out:
433      return -1;
434  }
435  
436  /*
437   * Parse an encoded NSS_P12_AuthenticatedSafe
438   */
439  static 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;
454  out:
455      return -1;
456  }
457  
458  static 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;
500  out:
501      return -1;
502  }
503  
504  p12_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;
522  out:
523      return err;
524  }