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