/ OSX / libsecurity_keychain / lib / SecImportExportPkcs8.cpp
SecImportExportPkcs8.cpp
  1  /*
  2   * Copyright (c) 2000-2004,2011-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  /*
 25   * SecImportExportPkcs8.cpp - support for generating and parsing/decoding 
 26   * private keys in PKCS8 format.  
 27   *
 28   * The current version (as of March 12 2004) can parse and decode every 
 29   * PKCS8 blob generated by openssl with the exception of those using 
 30   * double DES encryption. This has been verified by actually generating 
 31   * those blobs with openssl and decoding them here. 
 32   *
 33   * PLEASE: don't even *think* about changing a single line of code here 
 34   * without verifying the results against the full import/export regression
 35   * test in SecurityTests/clxutils/importExport. 
 36   * 
 37   */
 38  
 39  #include <Security/SecImportExport.h>
 40  #include "SecImportExportPkcs8.h"
 41  #include "SecPkcs8Templates.h"
 42  #include "SecImportExportUtils.h"
 43  #include "SecImportExportCrypto.h"
 44  #include <security_pkcs12/pkcs12Utils.h>
 45  #include <security_pkcs12/pkcs12Crypto.h>
 46  #include <security_asn1/SecNssCoder.h>
 47  #include <Security/keyTemplates.h>	
 48  #include <Security/SecAsn1Templates.h>	
 49  #include <Security/secasn1t.h>
 50  #include <security_asn1/nssUtils.h>
 51  #include <security_utilities/debugging.h>
 52  #include <Security/oidsalg.h>
 53  #include <Security/SecKeyPriv.h>
 54  #include <security_cdsa_utils/cuCdsaUtils.h>
 55  #include <openssl/pem.h>
 56  #include <security_utilities/simulatecrash_assert.h>
 57  #include <Security/SecBase.h>
 58  
 59  #define SecPkcs8Dbg(args...)	secinfo("SecPkcs8", ## args)
 60  
 61  #pragma mark --- PKCS5 v1.5 Key Derivation ---
 62  
 63  /*
 64   * PKCS5 v1.5. Caller has gleaned everything except salt, 
 65   * iterationCount, and IV from the AlgId.algorithm OID.
 66   *
 67   * We get salt and iteration count from the incoming alg params.
 68   * IV is derived along with the unwrapping key from the passphrase. 
 69   */
 70  static CSSM_RETURN pkcs5_v15_genKey(
 71  	CSSM_CSP_HANDLE			cspHand,
 72  	SecNssCoder				&coder,
 73  	const SecKeyImportExportParameters *keyParams,	
 74  	const CSSM_DATA			&paramData,
 75  	CSSM_ALGORITHMS			keyAlg, 
 76  	CSSM_ALGORITHMS			pbeHashAlg, 
 77  	uint32					keySizeInBits,
 78  	uint32					blockSizeInBytes,
 79  	impExpKeyUnwrapParams   *unwrapParams)
 80  {
 81  	CSSM_KEY				*passKey = NULL;
 82  	CFDataRef				cfPhrase = NULL;
 83  	CSSM_RETURN				crtn;
 84  	OSStatus				ortn;
 85  	CSSM_CRYPTO_DATA		seed;
 86  	CSSM_CC_HANDLE			ccHand = 0;
 87  	CSSM_ACCESS_CREDENTIALS	creds;
 88  	
 89  	
 90  	/* passphrase or passkey? */
 91  	ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, VP_Import,
 92  		(CFTypeRef *)&cfPhrase, &passKey);
 93  	if(ortn) {
 94  		return ortn;
 95  	}
 96  	/* subsequent errors to errOut: */
 97  	
 98  	memset(&seed, 0, sizeof(seed));
 99  	if(cfPhrase != NULL) {
100  		size_t len = CFDataGetLength(cfPhrase);
101  		coder.allocItem(seed.Param, len);
102  		memmove(seed.Param.Data, CFDataGetBytePtr(cfPhrase), len);
103  		CFRelease(cfPhrase);
104  	}
105  
106  	/* hash algorithm --> PBE alg for CSP */
107  	CSSM_ALGORITHMS		pbeAlg;
108  	switch(pbeHashAlg) {
109  		case CSSM_ALGID_MD2:
110  			pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_MD2;
111  			break;
112  		case CSSM_ALGID_MD5:
113  			pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_MD5;
114  			break;
115  		case CSSM_ALGID_SHA1:
116  			pbeAlg = CSSM_ALGID_PKCS5_PBKDF1_SHA1;
117  			break;
118  		default:
119  			/* really shouldn't happen - pbeHashAlg was inferred by 
120  			 * pkcsOidToParams() */
121  			SecPkcs8Dbg("PKCS8: PKCS5 v1/5 bogus hash alg");
122  			crtn = CSSMERR_CSP_INTERNAL_ERROR;
123  			goto errOut;
124  	}
125  	
126  	/* Salt and iteration count from alg parameters */
127  	impExpPKCS5_PBE_Parameters pbeParams;
128  	memset(&pbeParams, 0, sizeof(pbeParams));
129  	if(coder.decodeItem(paramData, impExpPKCS5_PBE_ParametersTemplate, &pbeParams)) {
130  		SecPkcs8Dbg("PKCS8: PKCS5 v1.5 pbeParams decode error");
131  		crtn = errSecUnknownFormat;
132  		goto errOut;
133  	}
134  	uint32 iterCount;
135  	if(!p12DataToInt(pbeParams.iterations, iterCount)) {
136  		SecPkcs8Dbg("PKCS8: bad PKCS5 v1.5 iteration count");
137  		crtn = errSecUnknownFormat;
138  		goto errOut;
139  	}
140  
141  	/* ask for hard coded 8 bytes of IV */
142  	coder.allocItem(unwrapParams->iv, 8);
143  	
144  	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
145  	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
146  		pbeAlg,
147  		keyAlg,
148  		keySizeInBits,
149  		&creds,
150  		passKey,		// BaseKey
151  		iterCount,
152  		&pbeParams.salt,
153  		&seed,	
154  		&ccHand);
155  	if(crtn) {
156  		SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_CSP_CreateDeriveKeyContext failure");
157  		goto errOut;
158  	}
159  	
160  	memset(unwrapParams->unwrappingKey, 0, sizeof(CSSM_KEY));
161  
162  	CSSM_DATA		dummyLabel;
163  	dummyLabel.Data = (uint8 *)"temp unwrap key";
164  	dummyLabel.Length = strlen((char *)dummyLabel.Data);
165  	
166  	crtn = CSSM_DeriveKey(ccHand,
167  		&unwrapParams->iv,		// IV returned in in/out Param
168  		CSSM_KEYUSE_ANY,
169  		/* not extractable even for the short time this key lives */
170  		CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
171  		&dummyLabel,
172  		NULL,			// cred and acl
173  		unwrapParams->unwrappingKey);
174  	if(crtn) {
175  		SecPkcs8Dbg("PKCS8: PKCS5 v1.5 CSSM_DeriveKey failure");
176  	}
177  errOut:
178  	if(ccHand != 0) {
179  		CSSM_DeleteContext(ccHand);
180  	}
181  	if(passKey != NULL) {
182  		CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
183  		free(passKey);
184  	}
185  	return crtn;
186  }
187  
188  #pragma mark --- PKCS5 v2.0 Key Derivation ---
189  
190  /*
191   * PKCS5 v2.0 has different means of encoding algorithm parameters, 
192   * depending on the encryption algorithm.
193   */
194  /*
195   * Obtain encryption parameters for PKCS5 v2.0, DES and DES3 variants.
196   */
197  static OSStatus pkcs5_DES_params(
198  	const CSSM_DATA			&paramData,		// encryptionScheme.parameters
199  	CSSM_OID				*encrOid,
200  	impExpKeyUnwrapParams   *unwrapParams,	
201  	CSSM_ALGORITHMS			*keyAlg,		// RETURNED
202  	uint32					*keySizeInBits, // IN/OUT (returned if 0 on entry)
203  	SecNssCoder				&coder)
204  {
205  	/* Params is iv as OCTET STRING */
206  	if(coder.decodeItem(paramData, kSecAsn1OctetStringTemplate, &unwrapParams->iv)) {
207  		SecPkcs8Dbg("PKCS8: PKCS5 v2 DES init vector decode error");
208  		return errSecUnknownFormat;
209  	}
210  	if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_DES_EDE3_CBC)) {
211  		*keyAlg = CSSM_ALGID_3DES_3KEY;
212  		unwrapParams->encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
213  		if(*keySizeInBits == 0) {
214  			*keySizeInBits = 3 * 64;
215  		}
216  	}
217  	else {
218  		*keyAlg = CSSM_ALGID_DES;
219  		unwrapParams->encrAlg = CSSM_ALGID_DES;
220  		if(*keySizeInBits == 0) {
221  			*keySizeInBits = 64;
222  		}
223  	}
224  	unwrapParams->encrPad  = CSSM_PADDING_PKCS7;
225  	unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
226  	return errSecSuccess;
227  }
228  
229  /*
230   * Obtain encryption parameters for PKCS5 v2.0, RC2 variant. 
231   */
232  static OSStatus pkcs5_RC2_params(
233  	const CSSM_DATA			&paramData,		// encryptionScheme.parameters
234  	impExpKeyUnwrapParams   *unwrapParams,	
235  	CSSM_ALGORITHMS			*keyAlg,		// RETURNED
236  	uint32					*keySizeInBits, // IN/OUT (returned if 0 on entry)
237  	SecNssCoder				&coder)
238  {
239  	/* Params is impExpPKCS5_RC2Params */
240  	impExpPKCS5_RC2Params rc2Params;
241  	memset(&rc2Params, 0, sizeof(rc2Params));
242  	if(coder.decodeItem(paramData, impExpPKCS5_RC2ParamsTemplate, &rc2Params)) {
243  		SecPkcs8Dbg("PKCS8: PKCS5 v2 RC2 params decode error");
244  		return errSecUnknownFormat;
245  	}
246  
247  	*keyAlg = CSSM_ALGID_RC2;
248  	unwrapParams->encrAlg  = CSSM_ALGID_RC2;
249  	unwrapParams->encrPad  = CSSM_PADDING_PKCS7;
250  	unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
251  
252  	/* the version actually maps to effective key size like this */
253  	/* I swear all of this is in the PKCS5 v2.0 spec */
254  	unwrapParams->effectiveKeySizeInBits = 32;		// default
255  	if(rc2Params.version.Data) {
256  		uint32 v;
257  		if(!p12DataToInt(rc2Params.version, v)) {
258  			SecPkcs8Dbg("PKCS8: bad PKCS5 rc2Params.version");
259  			return errSecUnknownFormat;
260  		}
261  		switch(v) {
262  			case 160:
263  				unwrapParams->effectiveKeySizeInBits = 40; 
264  				break;
265  			case 120: 
266  				unwrapParams->effectiveKeySizeInBits = 64; 
267  				break;
268  			case 58:  
269  				unwrapParams->effectiveKeySizeInBits = 128; 
270  				break;
271  			default:
272  				if(v >= 256) {
273  					unwrapParams->effectiveKeySizeInBits = v;
274  				}
275  				else {
276  					/* not in the spec, use as zero */
277  				}
278  				break;
279  		}
280  	}
281  	unwrapParams->iv = rc2Params.iv;
282  	
283  	/* the PKCS5 spec does not give a default for the RC2 key size */
284  	if(*keySizeInBits == 0) {
285  		SecPkcs8Dbg("PKCS8: NO RC2 DEFAULT KEYSIZE!");
286  		return errSecUnknownFormat;
287  	}
288  	return errSecSuccess;
289  }
290  
291  /*
292   * Infer encryption parameters for PKCS5 v2.0, RC5 variant. 
293   * All info contained in encryptionScheme.parameters. 
294   */
295  static OSStatus pkcs5_RC5_params(
296  	const CSSM_DATA			&paramData,		// encryptionScheme.parameters
297  	impExpKeyUnwrapParams   *unwrapParams,	
298  	CSSM_ALGORITHMS			*keyAlg,		// RETURNED
299  	uint32					*keySizeInBits, // IN/OUT (returned if 0 on entry)
300  	SecNssCoder				&coder)
301  {
302  	/* Params is a impExpPKCS5_RC5Params */
303  	impExpPKCS5_RC5Params rc5Params;
304  	memset(&rc5Params, 0, sizeof(rc5Params));
305  	if(coder.decodeItem(paramData, impExpPKCS5_RC5ParamsTemplate, &rc5Params)) {
306  		SecPkcs8Dbg("PKCS8: PKCS5 v2 RC5 params decode error");
307  		return errSecUnknownFormat;
308  	}
309  
310  	*keyAlg = CSSM_ALGID_RC5;
311  	unwrapParams->encrAlg  = CSSM_ALGID_RC5;
312  	unwrapParams->encrPad  = CSSM_PADDING_PKCS7;
313  	unwrapParams->encrMode = CSSM_ALGMODE_CBCPadIV8;
314  
315  	if(rc5Params.rounds.Data) {
316  		if(!p12DataToInt(rc5Params.rounds, unwrapParams->rounds)) {
317  			SecPkcs8Dbg("PKCS8: bad PKCS5 rc5Params.rounds");
318  			return errSecUnknownFormat;
319  		}
320  	}
321  	if(rc5Params.blockSizeInBits.Data) {
322  		if(!p12DataToInt(rc5Params.blockSizeInBits, unwrapParams->blockSizeInBits)) {
323  			SecPkcs8Dbg("PKCS8: bad PKCS5 rc5Params.blockSizeInBits");
324  			return errSecUnknownFormat;
325  		}
326  	}
327  	
328  	/* Spec says default iv is zeroes */
329  	unwrapParams->iv = rc5Params.iv;
330  	if(unwrapParams->iv.Length == 0) {
331  		uint32 len = unwrapParams->blockSizeInBits / 8;
332  		coder.allocItem(unwrapParams->iv, len);
333  		memset(unwrapParams->iv.Data, 0, len);
334  	}
335  	
336  	/*
337  	 * Spec does not give a default for key RC5 size, and openssl doesn't 
338  	 * support RC5 for PKCS8.
339  	 */
340  	if(*keySizeInBits == 0) {
341  		SecPkcs8Dbg("PKCS8: NO RC5 DEFAULT KEYSIZE!");
342  		return errSecUnknownFormat;
343  	}
344  	return errSecSuccess;
345  }
346  
347  /* 
348   * Common code to derive a wrap/unwrap key using PBKDF2 (i.e., using PKCS5 v2.0
349   * key derivation). Caller must CSSM_FreeKey when done. 
350   */
351  static CSSM_RETURN pbkdf2DeriveKey(
352  	CSSM_CSP_HANDLE		cspHand,
353  	SecNssCoder			&coder,
354  	CSSM_ALGORITHMS		keyAlg,
355  	uint32				keySizeInBits,
356  	uint32				iterationCount,
357  	const CSSM_DATA		&salt,
358  	const SecKeyImportExportParameters	*keyParams,		// required 
359  	impExpVerifyPhrase  verifyPhrase,   // for secure passphrase
360  	CSSM_KEY_PTR		symKey)							// RETURNED
361  {
362  	CSSM_KEY					*passKey = NULL;
363  	CFDataRef					cfPhrase = NULL;
364  	CSSM_PKCS5_PBKDF2_PARAMS 	pbeParams;
365  	CSSM_RETURN					crtn;
366  	OSStatus					ortn;
367  	CSSM_DATA					dummyLabel;
368  	CSSM_DATA					pbeData;
369  	uint32						keyAttr;
370  	CSSM_CC_HANDLE 				ccHand = 0;
371  	CSSM_ACCESS_CREDENTIALS		creds;
372  	
373  	memset(&pbeParams, 0, sizeof(pbeParams));
374  
375  	/* passphrase or passkey? */
376  	ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_Data, verifyPhrase,
377  		(CFTypeRef *)&cfPhrase, &passKey);
378  	if(ortn) {
379  		return ortn;
380  	}
381  	/* subsequent errors to errOut: */
382  
383  	if(cfPhrase != NULL) {
384  		size_t len = CFDataGetLength(cfPhrase);
385  		coder.allocItem(pbeParams.Passphrase, len);
386  		memmove(pbeParams.Passphrase.Data, 
387  			CFDataGetBytePtr(cfPhrase), len);
388  		CFRelease(cfPhrase);
389  	}
390  
391  	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
392  	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
393  		CSSM_ALGID_PKCS5_PBKDF2,
394  		keyAlg,
395  		keySizeInBits,
396  		&creds,
397  		passKey,		// BaseKey
398  		iterationCount,
399  		&salt,
400  		NULL,			// seed
401  		&ccHand);
402  	if(crtn) {
403  		SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_CSP_CreateDeriveKeyContext failure");
404  		goto errOut;
405  	}
406  	
407  	memset(symKey, 0, sizeof(CSSM_KEY));
408  
409  	/* not extractable even for the short time this key lives */
410  	keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE;
411  	dummyLabel.Data = (uint8 *)"temp unwrap key";
412  	dummyLabel.Length = strlen((char *)dummyLabel.Data);
413  	
414  	pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
415  	pbeData.Data = (uint8 *)&pbeParams;
416  	pbeData.Length = sizeof(pbeParams);
417  	crtn = CSSM_DeriveKey(ccHand,
418  		&pbeData,
419  		CSSM_KEYUSE_ANY,
420  		keyAttr,
421  		&dummyLabel,
422  		NULL,			// cred and acl
423  		symKey);
424  	if(crtn) {
425  		SecPkcs8Dbg("PKCS8: PKCS5 v2 CSSM_DeriveKey failure");
426  	}
427  errOut:
428  	if(ccHand != 0) {
429  		CSSM_DeleteContext(ccHand);
430  	}
431  	if(passKey != NULL) {
432  		CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
433  		free(passKey);
434  	}
435  	return crtn;
436  }
437  
438  /* 
439   * Obtain PKCS5, v.2.0 key derivation and encryption parameters and 
440   * derive the key. This one obtains all of the crypt parameters 
441   * from the top-level AlgId.Params. What a mess. 
442   */
443  static CSSM_RETURN pkcs5_v2_genKey(
444  	CSSM_CSP_HANDLE			cspHand,
445  	SecNssCoder				&coder,
446  	const CSSM_DATA			&paramData,
447  	const SecKeyImportExportParameters *keyParams,
448  	impExpKeyUnwrapParams   *unwrapParams)
449  {
450  	SecPkcs8Dbg("PKCS8: generating PKCS5 v2.0 key");
451  
452  	CSSM_ALGORITHMS		keyAlg = CSSM_ALGID_NONE;
453  	uint32				prf = 0;		// CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1...
454  	
455  	/* caller should check */
456  	assert(keyParams != NULL);
457  
458  	/* AlgId.Params --> impExpPKCS5_PBES2_Params */
459  	if(paramData.Length == 0) {
460  		SecPkcs8Dbg("PKCS8: empty PKCS5 v2 pbes2Params");
461  		return errSecUnknownFormat;
462  	}
463  	impExpPKCS5_PBES2_Params pbes2Params;
464  	memset(&pbes2Params, 0, sizeof(pbes2Params));
465  	if(coder.decodeItem(paramData, impExpPKCS5_PBES2_ParamsTemplate, &pbes2Params)) {
466  		SecPkcs8Dbg("PKCS8: PKCS5 v2 pbes2Params decode error");
467  		return errSecUnknownFormat;
468  	}
469  	
470  	/*
471  	 * As far as I know the keyDerivationFunc OID must be id-PBKDF2 
472  	 */
473  	if(!nssCompareCssmData(&pbes2Params.keyDerivationFunc.algorithm, 
474  			&CSSMOID_PKCS5_PBKDF2)) {
475  		SecPkcs8Dbg("PKCS8: PKCS5 v2 unexpected keyDerivationFunc alg");
476  		return errSecUnknownFormat;
477  	}
478  	
479  	/*
480  	 * The params of the keyDerivationFunc algId are an encoded 
481  	 * impExpPKCS5_PBKDF2_Params.
482  	 */
483  	impExpPKCS5_PBKDF2_Params pbkdf2Params;
484  	memset(&pbkdf2Params, 0, sizeof(pbkdf2Params));
485  	if(coder.decodeItem(pbes2Params.keyDerivationFunc.parameters,
486  			impExpPKCS5_PBKDF2_ParamsTemplate, &pbkdf2Params)) {
487  		SecPkcs8Dbg("PKCS8: PKCS5 v2 pbkdf2Params decode error");
488  		return errSecUnknownFormat;
489  	}
490  	
491  	/*
492  	 * Salt and iteration count from the impExpPKCS5_PBKDF2_Params (ignoring the 
493  	 * possible CHOICE for salt source).
494  	 */
495  	CSSM_DATA salt = pbkdf2Params.salt;
496  	uint32 iterCount;
497  	if(!p12DataToInt(pbkdf2Params.iterationCount, iterCount)) {
498  		SecPkcs8Dbg("PKCS8: bad PKCS5 v2 iteration count");
499  		return errSecUnknownFormat;
500  	}
501  	
502  	/*
503  	 * Key size optional, use defaults per alg (later) if it's not there
504  	 */
505  	uint32 keySizeInBits = 0;
506  	if(pbkdf2Params.keyLengthInBytes.Data) {
507  		uint32 keyLengthInBytes;
508  		if(!p12DataToInt(pbkdf2Params.keyLengthInBytes, keyLengthInBytes)) {
509  			SecPkcs8Dbg("PKCS8: bad PKCS5 v2 key size");
510  			return errSecUnknownFormat;
511  		}
512  		keySizeInBits = keyLengthInBytes * 8;
513  	}
514  	/* else we'll infer key size from the encryption algorithm */
515  	
516  	/* prf optional, but if it's there it better be CSSMOID_PKCS5_HMAC_SHA1 */
517  	if(pbkdf2Params.prf.Data) {
518  		if(!nssCompareCssmData(&pbkdf2Params.prf, &CSSMOID_PKCS5_HMAC_SHA1)) {
519  			SecPkcs8Dbg("PKCS8: PKCS5 v2 unexpected prf OID");
520  			return errSecUnknownFormat;
521  		}
522  	}
523  	prf = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
524  
525  	/*
526  	 * Now process the encryptionScheme, which is even messier - the algParams
527  	 * varies per encryption algorithm.
528  	 */
529  	CSSM_X509_ALGORITHM_IDENTIFIER &encrScheme = pbes2Params.encryptionScheme;
530  	CSSM_OID *encrOid = &encrScheme.algorithm;
531  	OSStatus ortn;
532  	CSSM_DATA &encrParam = encrScheme.parameters;
533  	
534  	if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_DES_EDE3_CBC) ||
535  	   nssCompareCssmData(encrOid, &CSSMOID_DES_CBC)) {
536  		ortn = pkcs5_DES_params(encrParam, encrOid, unwrapParams, &keyAlg, 
537  			&keySizeInBits, coder);
538  		if(ortn) {
539  			return ortn;
540  		}
541  	}
542  	else if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_RC2_CBC)) {
543  		ortn = pkcs5_RC2_params(encrParam, unwrapParams, &keyAlg, 
544  			&keySizeInBits, coder);
545  		if(ortn) {
546  			return ortn;
547  		}
548  	}
549  	else if(nssCompareCssmData(encrOid, &CSSMOID_PKCS5_RC5_CBC)) {
550  		ortn = pkcs5_RC5_params(encrParam, unwrapParams, &keyAlg, 
551  			&keySizeInBits, coder);
552  		if(ortn) {
553  			return ortn;
554  		}
555  	}
556  	else {
557  		SecPkcs8Dbg("PKCS8: PKCS5 v2 unknown encrScheme.algorithm");
558  		return errSecUnknownFormat;
559  	}
560  	
561  	/* We should be ready to go */
562  	assert(keyAlg != CSSM_ALGID_NONE);
563  	assert(unwrapParams->encrAlg != CSSM_ALGID_NONE);
564  	
565  	/* use all the stuff we just figured out to derive a symmetric decryption key */
566  	return pbkdf2DeriveKey(cspHand, coder,
567  		keyAlg, keySizeInBits, 
568  		iterCount, salt,
569  		keyParams, 
570  		VP_Import,
571  		unwrapParams->unwrappingKey);
572  }
573  
574  #pragma mark --- PKCS12 Key Derivation ---
575  
576  /*
577   * PKCS12 style key derivation. Caller has gleaned everything except 
578   * salt, iterationCount, and IV from the AlgId.algorithm OID.
579   *
580   * We get salt and iteration count from the incoming alg params.
581   * IV is derived along with the unwrapping key from the passphrase. 
582   */
583  static CSSM_RETURN pkcs12_genKey(
584  	CSSM_CSP_HANDLE		cspHand,
585  	SecNssCoder			&coder,
586  	const SecKeyImportExportParameters *keyParams,
587  	const CSSM_DATA		&paramData,			// from algID
588  	CSSM_ALGORITHMS		keyAlg,				// valid on entry 
589  	CSSM_ALGORITHMS		pbeHashAlg,			// valid on entry 
590  	uint32				keySizeInBits,		// valid on entry
591  	uint32				blockSizeInBytes,   // for IV
592  	impExpKeyUnwrapParams  *unwrapParams)
593  {
594  	SecPkcs8Dbg("PKCS8: generating PKCS12 key");
595  	
596  	assert(keyAlg != CSSM_ALGID_NONE);
597  	assert(pbeHashAlg != CSSM_ALGID_NONE);
598  	assert(keySizeInBits != 0);
599  	
600  	/* get iteration count, salt from alg params */
601  	NSS_P12_PBE_Params pbeParams;
602  	
603  	if(paramData.Length == 0) {
604  		SecPkcs8Dbg("PKCS8: empty P12 pbeParams");
605  		return errSecUnknownFormat;
606  	}
607  	memset(&pbeParams, 0, sizeof(pbeParams));
608  	if(coder.decodeItem(paramData, NSS_P12_PBE_ParamsTemplate, &pbeParams)) {
609  		SecPkcs8Dbg("PKCS8: P12 pbeParams decode error");
610  		return errSecUnknownFormat;
611  	}
612  
613  	uint32 iterCount = 0;
614  	if(!p12DataToInt(pbeParams.iterations, iterCount)) {
615  		SecPkcs8Dbg("PKCS8: bad P12 iteration count");
616  		return errSecUnknownFormat;
617  	}
618  	
619  	/* passphrase or passkey? */
620  	CSSM_KEY *passKey = NULL;
621  	CFStringRef phraseStr = NULL;
622  	CSSM_DATA phraseData = {0, NULL};
623  	CSSM_DATA *phraseDataP = NULL;
624  	OSStatus ortn;
625  	CSSM_RETURN crtn;
626  	
627  	assert(keyParams != NULL);
628  	
629  	ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String, VP_Import,
630  		(CFTypeRef *)&phraseStr, &passKey);
631  	if(ortn) {
632  		return ortn;
633  	}
634  	/* subsequent errors to errOut: */
635  	
636  	if(phraseStr != NULL) {
637  		/* convert to CSSM_DATA for use with p12KeyGen() */
638  		try {
639  			p12ImportPassPhrase(phraseStr, coder, phraseData);		
640  		} 
641  		catch(...) {
642  			SecPkcs8Dbg("PKCS8: p12ImportPassPhrase threw");
643  			crtn = errSecAllocate;
644  			goto errOut;
645  		}
646  		CFRelease(phraseStr);
647  		phraseDataP = &phraseData;
648  	}   
649  	
650  	/* use p12 module to cook up the key and IV */
651  	if(blockSizeInBytes) {
652  		coder.allocItem(unwrapParams->iv, blockSizeInBytes);
653  	}
654  	crtn = p12KeyGen(cspHand, 
655  		*unwrapParams->unwrappingKey,
656  		true,		// isForEncr
657  		keyAlg,
658  		pbeHashAlg,
659  		keySizeInBits,
660  		iterCount,
661  		pbeParams.salt,
662  		phraseDataP,
663  		passKey,
664  		unwrapParams->iv);
665  	if(crtn) {
666  		SecPkcs8Dbg("PKCS8: p12KeyGen failed");
667  	}
668  errOut:
669  	if(passKey != NULL) {
670  		CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE);
671  		free(passKey);
672  	}
673  	return crtn;
674  }
675  
676  #pragma mark --- Public PKCS8 import function ---
677  
678  /* 
679   * Called out from SecImportRep::importWrappedKey().
680   * If cspHand is provided instead of importKeychain, the CSP 
681   * handle MUST be for the CSPDL, not for the raw CSP.
682   */
683  OSStatus impExpPkcs8Import(
684  	CFDataRef							inData,
685  	SecKeychainRef						importKeychain, // optional
686  	CSSM_CSP_HANDLE						cspHand,		// required
687  	SecItemImportExportFlags			flags,
688  	const SecKeyImportExportParameters	*keyParams,		// REQUIRED for unwrap 
689  	CFMutableArrayRef					outArray)		// optional, append here 
690  {
691  	CSSM_KEY			wrappedKey;
692  	CSSM_KEYHEADER		&hdr = wrappedKey.KeyHeader;
693  	CSSM_RETURN			crtn = CSSM_OK;
694  	
695  	/* key derivation and encryption parameters gleaned from alg ID */
696  	impExpKeyUnwrapParams unwrapParams;
697  	memset(&unwrapParams, 0, sizeof(unwrapParams));
698  	CSSM_ALGORITHMS		keyAlg = CSSM_ALGID_NONE;
699  	CSSM_ALGORITHMS		pbeHashAlg = CSSM_ALGID_NONE;	// SHA1 or MD5
700  	uint32				keySizeInBits;
701  	uint32				blockSizeInBytes;
702  	PKCS_Which			pkcs = PW_None;			
703  	
704  	if( (keyParams == NULL) ||
705  	    ( (keyParams->passphrase == NULL) && 
706  		  !(keyParams->flags & kSecKeySecurePassphrase) ) ) {
707  		/* passphrase mandatory */
708  		return errSecPassphraseRequired;
709  	}
710  	assert(cspHand != 0);
711  	
712  	/*
713  	 * Top-level decode 
714  	 */
715  	SecNssCoder					coder;
716  	NSS_EncryptedPrivateKeyInfo encrPrivKeyInfo;
717  	
718  	memset(&encrPrivKeyInfo, 0, sizeof(encrPrivKeyInfo));
719  	if(coder.decode(CFDataGetBytePtr(inData),
720  			CFDataGetLength(inData),
721  			kSecAsn1EncryptedPrivateKeyInfoTemplate, &encrPrivKeyInfo)) {
722  		SecImpExpDbg("impExpPkcs8Import: error decoding top-level encrPrivKeyInfo");
723  		return errSecUnknownFormat;
724  	}
725  	
726  	/*
727  	 * The algorithm OID of that top-level struct is the key piece of info 
728  	 * for now...
729  	 */
730  	bool found = false;
731  	found = pkcsOidToParams(&encrPrivKeyInfo.algorithm.algorithm,
732  		keyAlg, unwrapParams.encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
733  		unwrapParams.encrPad, unwrapParams.encrMode, pkcs);
734  	if(!found) {
735  		SecImpExpDbg("impExpPkcs8Import: unknown OID in top-level encrPrivKeyInfo");
736  		return errSecUnknownFormat;
737  	}
738  	
739  	/* 
740  	 * Each PBE method has its own way of filling in the remaining gaps
741  	 * in impExpKeyUnwrapParams and generating a key.
742  	 */
743  	CSSM_KEY unwrappingKey;
744  	memset(&unwrappingKey, 0, sizeof(unwrappingKey));
745  	unwrapParams.unwrappingKey = &unwrappingKey;
746  	CSSM_DATA &paramData = encrPrivKeyInfo.algorithm.parameters;
747  
748  	switch(pkcs) {
749  		case PW_PKCS5_v1_5:
750  			/* we have everything except iv, iterations, salt */
751  			crtn = pkcs5_v15_genKey(cspHand, coder, keyParams, paramData,
752  				keyAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
753  				&unwrapParams);
754  			break;
755  			
756  		case PW_PKCS5_v2:
757  			/* obtain everything, including iv, from alg params */
758  			crtn = pkcs5_v2_genKey(cspHand, coder, paramData, keyParams, &unwrapParams);
759  			break;
760  		case PW_PKCS12:
761  			/* we have everything except iv, iterations, salt */
762  			crtn = pkcs12_genKey(cspHand, coder, keyParams, paramData,
763  				keyAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
764  				&unwrapParams);
765  			break;
766  		case PW_None:
767  			/* satisfy compiler */
768  			assert(0);
769  			return errSecUnknownFormat; 
770  	}
771  	if(crtn) {
772  		SecPkcs8Dbg("PKCS8: key derivation failed");
773  		return crtn;
774  	}
775  	
776  	/* we should be ready to rock'n'roll no matter how we got here */
777  	assert(unwrapParams.encrAlg != CSSM_ALGID_NONE);
778  	assert(unwrappingKey.KeyData.Data != NULL);
779  	assert(unwrappingKey.KeyHeader.AlgorithmId != CSSM_ALGID_NONE);
780  	
781  	/* set up key to unwrap */
782  	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
783  	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
784  	/* CspId : don't care */
785  	hdr.BlobType = CSSM_KEYBLOB_WRAPPED;
786  	hdr.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
787  	/* AlgorithmId : inferred by CSP */
788  	hdr.AlgorithmId = CSSM_ALGID_NONE;
789  	hdr.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
790  	/* LogicalKeySizeInBits : calculated by CSP during unwrap */
791  	hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
792  	hdr.KeyUsage = CSSM_KEYUSE_ANY;
793  
794  	wrappedKey.KeyData = encrPrivKeyInfo.encryptedData;
795  
796  	crtn = impExpImportKeyCommon(
797  		&wrappedKey,
798  		importKeychain,
799  		cspHand,
800  		flags,
801  		keyParams,
802  		&unwrapParams,
803  		NULL,			// default label 
804  		outArray);
805  	CSSM_FreeKey(cspHand, NULL, &unwrappingKey, CSSM_FALSE);
806  	return crtn;
807  }
808  
809  #pragma mark --- Public PKCS8 export function ---
810  
811  #define PKCS5_V2_SALT_LEN		8
812  #define PKCS5_V2_ITERATIONS		2048
813  #define PKCS5_V2_DES_IV_SIZE	8
814  
815  /*
816   * Unlike impExpPkcs8Import(), which can handle every PBE algorithm in the spec
817   * and implemented by openssl, this one has a fixed PBE and encryption scheme. 
818   * We do not provide a means at the API for the client to specify these. 
819   *
820   * We generate blobs with triple DES encryption, with PKCS5 v2.0 key 
821   * derivation.
822   */
823  OSStatus impExpPkcs8Export(
824  	SecKeyRef							secKey,
825  	SecItemImportExportFlags			flags,		
826  	const SecKeyImportExportParameters	*keyParams,		// optional 
827  	CFMutableDataRef					outData,		// output appended here
828  	const char							**pemHeader)	
829  {
830  	SecNssCoder						coder;
831  	impExpPKCS5_PBES2_Params		pbes2Params;
832  	CSSM_X509_ALGORITHM_IDENTIFIER  &keyDeriveAlgId = pbes2Params.keyDerivationFunc;
833  	CSSM_ATTRIBUTE_TYPE				formatAttrType = CSSM_ATTRIBUTE_NONE;
834  	CSSM_KEYBLOB_FORMAT				blobForm = CSSM_KEYBLOB_RAW_FORMAT_NONE;
835  	const CSSM_KEY					*cssmKey;
836  	
837  	if(keyParams == NULL) {
838  		return errSecParam;
839  	}
840  	assert(secKey != NULL);
841  	assert(outData != NULL);
842  	
843  	memset(&pbes2Params, 0, sizeof(pbes2Params));
844  	
845  	/* 
846  	 * keyDeriveAlgId
847  	 * parameters is an encoded impExpPKCS5_PBKDF2_Params 
848  	 * We generate random salt
849  	 */
850  	keyDeriveAlgId.algorithm = CSSMOID_PKCS5_PBKDF2;
851  	impExpPKCS5_PBKDF2_Params pbkdf2Params;
852  	memset(&pbkdf2Params, 0, sizeof(pbkdf2Params));
853  	coder.allocItem(pbkdf2Params.salt, PKCS5_V2_SALT_LEN);
854      MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, PKCS5_V2_SALT_LEN, pbkdf2Params.salt.Data));
855      
856  	p12IntToData(PKCS5_V2_ITERATIONS, pbkdf2Params.iterationCount, coder);
857  	/* leave pbkdf2Params.keyLengthInBytes NULL for default */
858  	/* openssl can't handle this, which is the default value:
859  	   pbkdf2Params.prf = CSSMOID_PKCS5_HMAC_SHA1;
860  	 */
861  	
862  	coder.encodeItem(&pbkdf2Params, impExpPKCS5_PBKDF2_ParamsTemplate,
863  			keyDeriveAlgId.parameters);
864  
865  	/*
866  	 * encryptionScheme
867  	 * parameters is an encoded OCTET STRING containing the (random) IV
868  	 */
869  	CSSM_X509_ALGORITHM_IDENTIFIER &encrScheme = pbes2Params.encryptionScheme;
870  	encrScheme.algorithm = CSSMOID_PKCS5_DES_EDE3_CBC;
871  	CSSM_DATA rawIv = {0, NULL};
872  	coder.allocItem(rawIv, PKCS5_V2_DES_IV_SIZE);
873      MacOSError::check(SecRandomCopyBytes(kSecRandomDefault, PKCS5_V2_DES_IV_SIZE, rawIv.Data));
874  
875  	coder.encodeItem(&rawIv, kSecAsn1OctetStringTemplate,
876  			encrScheme.parameters);
877  	
878  	/*
879  	 * Top level NSS_EncryptedPrivateKeyInfo, whose parameters is the encoded 
880  	 * impExpPKCS5_PBES2_Params. 
881  	 */
882  	NSS_EncryptedPrivateKeyInfo encrPrivKeyInfo;
883  	memset(&encrPrivKeyInfo, 0, sizeof(encrPrivKeyInfo));
884  	CSSM_X509_ALGORITHM_IDENTIFIER &topAlgId = encrPrivKeyInfo.algorithm;
885  	topAlgId.algorithm = CSSMOID_PKCS5_PBES2;
886  	coder.encodeItem(&pbes2Params, impExpPKCS5_PBES2_ParamsTemplate,
887  			topAlgId.parameters);
888  			
889  	/*
890  	 * Now all we have to do is generate the encrypted key data itself. 
891  	 * When doing a WrapKey op in PKCS8 form, the CSP gives us the 
892  	 * NSS_EncryptedPrivateKeyInfo.encryptedData values. 
893  	 */
894  	
895  	/* we need a CSPDL handle - try to get it from the key */
896  	CSSM_CSP_HANDLE cspdlHand = 0;
897  	OSStatus ortn;
898  	bool releaseCspHand = false;
899  	CSSM_DATA encodedKeyInfo = {0, NULL};
900  	
901  	ortn = SecKeyGetCSPHandle(secKey, &cspdlHand);
902  	if(ortn) {
903  		cspdlHand = cuCspStartup(CSSM_FALSE);
904  		if(cspdlHand == 0) {
905  			return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
906  		}
907  		releaseCspHand = true;
908  	}
909  	/* subsequent errors to errOut: */
910  	
911  	/* get wrapping key from parameters we just set up */
912  	CSSM_KEY wrappingKey;
913  	memset(&wrappingKey, 0, sizeof(CSSM_KEY));
914  	CSSM_RETURN crtn = pbkdf2DeriveKey(cspdlHand, coder,
915  		CSSM_ALGID_3DES_3KEY, 3 * 64, 
916  		PKCS5_V2_ITERATIONS, pbkdf2Params.salt,
917  		keyParams,
918  		VP_Export,
919  		&wrappingKey);
920  	if(crtn) {
921  		goto errOut;
922  	}
923  
924  	/*
925  	 * Special case for DSA, ECDSA: specify that the raw blob, pre-encrypt, is in 
926  	 * the PKCS8 PrivateKeyInfo format that openssl understands. The
927  	 * default is BSAFE.
928  	 */
929  	crtn = SecKeyGetCSSMKey(secKey, &cssmKey);
930  	if(crtn) {
931  		SecImpExpDbg("impExpPkcs8Export SecKeyGetCSSMKey error");
932  		goto errOut;
933  	}
934  	switch(cssmKey->KeyHeader.AlgorithmId) {
935  		case CSSM_ALGID_DSA:
936  		case CSSM_ALGID_ECDSA:
937  			formatAttrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
938  			blobForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
939  			break;
940  		default:
941  			break;
942  	}
943  	
944  	/* GO */
945  	CSSM_KEY wrappedKey;
946  	memset(&wrappedKey, 0, sizeof(CSSM_KEY));
947  	
948  	crtn = impExpExportKeyCommon(cspdlHand, secKey, &wrappingKey, &wrappedKey,
949  		CSSM_ALGID_3DES_3KEY_EDE, CSSM_ALGMODE_CBCPadIV8, CSSM_PADDING_PKCS7,
950  		CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8, formatAttrType, blobForm, NULL, &rawIv);
951  	if(crtn) {
952  		goto errOut;
953  	}
954  	
955  	/*
956  	 * OK... *that* wrapped key's data goes into the top-level 
957  	 * NSS_EncryptedPrivateKeyInfo, which we then encode; the caller
958  	 * gets the result of that encoding. 
959  	 */
960  	encrPrivKeyInfo.encryptedData = wrappedKey.KeyData;
961  	coder.encodeItem(&encrPrivKeyInfo, kSecAsn1EncryptedPrivateKeyInfoTemplate,
962  			encodedKeyInfo);
963  	
964  	CFDataAppendBytes(outData, encodedKeyInfo.Data, encodedKeyInfo.Length);
965  	CSSM_FreeKey(cspdlHand, NULL, &wrappedKey, CSSM_FALSE);
966  	
967  	*pemHeader = PEM_STRING_PKCS8;
968  	
969  errOut:
970  	if(wrappingKey.KeyData.Data) {
971  		CSSM_FreeKey(cspdlHand, NULL, &wrappingKey, CSSM_FALSE);
972  	}
973  	if(releaseCspHand) {
974  		cuCspDetachUnload(cspdlHand, CSSM_FALSE);
975  	}
976  	return crtn;
977  }