1/*
2 * Copyright (c) 2003-2004 Apple Computer, 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 * pkcs12Decode.h - P12Coder decoding engine.
26 */
27
28#include "pkcs12Coder.h"
29#include "pkcs12Templates.h"
30#include "pkcs12Utils.h"
31#include "pkcs12Debug.h"
32#include "pkcs12Crypto.h"
33#include <security_cdsa_utilities/cssmerrors.h>
34#include <security_asn1/nssUtils.h>
35
36/* top-level PKCS12 PFX decoder */
37void P12Coder::decode(
38	CFDataRef				cdpfx)
39{
40	SecNssCoder localCdr;
41	NSS_P12_DecodedPFX pfx;
42
43	p12DecodeLog("decode");
44	memset(&pfx, 0, sizeof(pfx));
45	const CSSM_DATA rawBlob = {CFDataGetLength(cdpfx),
46		(uint8 *)CFDataGetBytePtr(cdpfx)};
47
48	if(localCdr.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) {
49		p12ErrorLog("Error on top-level decode of NSS_P12_DecodedPFX\n");
50		P12_THROW_DECODE;
51	}
52	NSS_P7_DecodedContentInfo &dci = pfx.authSafe;
53	if(dci.type != CT_Data) {
54		/* no other types supported yet */
55		p12ErrorLog("bad top-level contentType\n");
56		P12_THROW_DECODE;
57	}
58	mIntegrityMode = kSecPkcs12ModePassword;
59
60	if(pfx.macData == NULL) {
61		/* not present is an error in kSecPkcs12ModePassword */
62		p12ErrorLog("no MAC in PFX\n");
63		P12_THROW_DECODE;
64	}
65	macParse(*pfx.macData, localCdr);
66
67	const CSSM_DATA *macPhrase = getMacPassPhrase();
68	const CSSM_KEY *macPassKey = getMacPassKey();
69	if((macPhrase == NULL) && (macPassKey == NULL)) {
70		p12ErrorLog("no passphrase set\n");
71		CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE);
72	}
73	CSSM_RETURN crtn = p12VerifyMac(pfx, mCspHand, macPhrase,
74		macPassKey, localCdr);
75	if(crtn) {
76		p12LogCssmError("p12VerifyMac", crtn);
77		CssmError::throwMe(errSecPkcs12VerifyFailure);
78	}
79
80	authSafeParse(*dci.content.data, localCdr);
81
82	/*
83	 * On success, if we have a keychain, store certs and CRLs there
84	 */
85	if(mKeychain != NULL) {
86		storeDecodeResults();
87	}
88}
89
90/*
91 * Decrypt the contents of a NSS_P7_EncryptedData
92 */
93void P12Coder::encryptedDataDecrypt(
94	const NSS_P7_EncryptedData &edata,
95	SecNssCoder &localCdr,
96	NSS_P12_PBE_Params *pbep,	// preparsed
97	CSSM_DATA &ptext)			// result goes here in localCdr space
98{
99	p12DecodeLog("encryptedDataDecrypt");
100
101	/* see if we can grok the encr alg */
102	CSSM_ALGORITHMS		keyAlg;			// e.g., CSSM_ALGID_DES
103	CSSM_ALGORITHMS		encrAlg;		// e.g., CSSM_ALGID_3DES_3KEY_EDE
104	CSSM_ALGORITHMS		pbeHashAlg;		// SHA1 or MD5
105	uint32				keySizeInBits;
106	uint32				blockSizeInBytes;	// for IV, optional
107	CSSM_PADDING		padding;		// CSSM_PADDING_PKCS7, etc.
108	CSSM_ENCRYPT_MODE	mode;			// CSSM_ALGMODE_CBCPadIV8, etc.
109	PKCS_Which			pkcs;
110
111	bool found = pkcsOidToParams(&edata.contentInfo.encrAlg.algorithm,
112		keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
113		padding, mode, pkcs);
114	if(!found || (pkcs != PW_PKCS12)) {
115		p12ErrorLog("EncryptedData encrAlg not understood\n");
116		CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
117	}
118
119	uint32 iterCount;
120	if(!p12DataToInt(pbep->iterations, iterCount)) {
121		p12ErrorLog("encryptedDataDecrypt: badly formed iterCount\n");
122		P12_THROW_DECODE;
123	}
124	const CSSM_DATA *pwd = getEncrPassPhrase();
125	const CSSM_KEY *passKey = getEncrPassKey();
126	if((pwd == NULL) && (passKey == NULL)) {
127		p12ErrorLog("no passphrase set\n");
128		CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE);
129	}
130
131	/* go */
132	CSSM_RETURN crtn = p12Decrypt(mCspHand,
133		edata.contentInfo.encrContent,
134		keyAlg, encrAlg, pbeHashAlg,
135		keySizeInBits, blockSizeInBytes,
136		padding, mode,
137		iterCount, pbep->salt,
138		pwd,
139		passKey,
140		localCdr,
141		ptext);
142	if(crtn) {
143		CssmError::throwMe(crtn);
144	}
145}
146
147
148/*
149 * Parse an CSSM_X509_ALGORITHM_IDENTIFIER specific to P12.
150 * Decode the alg params as a NSS_P12_PBE_Params and parse and
151 * return the result if the pbeParams is non-NULL.
152 */
153void P12Coder::algIdParse(
154	const CSSM_X509_ALGORITHM_IDENTIFIER &algId,
155	NSS_P12_PBE_Params *pbeParams,		// optional
156	SecNssCoder &localCdr)
157{
158	p12DecodeLog("algIdParse");
159
160	const CSSM_DATA &param = algId.parameters;
161	if(pbeParams == NULL) {
162		/* alg params are uninterpreted */
163		return;
164	}
165
166	if(param.Length == 0) {
167		p12ErrorLog("algIdParse: no alg parameters\n");
168		P12_THROW_DECODE;
169	}
170
171	memset(pbeParams, 0, sizeof(*pbeParams));
172	if(localCdr.decodeItem(param,
173			NSS_P12_PBE_ParamsTemplate, pbeParams)) {
174		p12ErrorLog("Error decoding NSS_P12_PBE_Params\n");
175		P12_THROW_DECODE;
176	}
177}
178
179/*
180 * Parse a NSS_P7_EncryptedData - specifically in the context
181 * of a P12 in password privacy mode. (The latter assumption is
182 * to enable us to infer CSSM_X509_ALGORITHM_IDENTIFIER.parameters
183 * format).
184 */
185void P12Coder::encryptedDataParse(
186	const NSS_P7_EncryptedData &edata,
187	SecNssCoder &localCdr,
188	NSS_P12_PBE_Params *pbep)		// optional, RETURNED
189{
190	p12DecodeLog("encryptedDataParse");
191
192	/*
193	 * Parse the alg ID, save PBE params for when we do the decrypt
194	 * key unwrap
195	 */
196	const NSS_P7_EncrContentInfo &ci = edata.contentInfo;
197	const CSSM_X509_ALGORITHM_IDENTIFIER &algId = ci.encrAlg;
198	algIdParse(algId, pbep, localCdr);
199}
200
201/*
202 * ShroudedKeyBag parser w/decrypt
203 */
204void P12Coder::shroudedKeyBagParse(
205	const NSS_P12_SafeBag &safeBag,
206	SecNssCoder &localCdr)
207{
208	p12DecodeLog("Found shrouded key bag");
209	if(mPrivKeyImportState == PKIS_NoMore) {
210		CssmError::throwMe(errSecMultiplePrivKeys);
211	}
212
213	const NSS_P12_ShroudedKeyBag *keyBag = safeBag.bagValue.shroudedKeyBag;
214	const CSSM_X509_ALGORITHM_IDENTIFIER &algId = keyBag->algorithm;
215	NSS_P12_PBE_Params pbep;
216	algIdParse(algId, &pbep, localCdr);
217
218	/*
219	 * Prepare for decryption
220	 */
221	CSSM_ALGORITHMS		keyAlg;			// e.g., CSSM_ALGID_DES
222	CSSM_ALGORITHMS		encrAlg;		// e.g., CSSM_ALGID_3DES_3KEY_EDE
223	CSSM_ALGORITHMS		pbeHashAlg;		// SHA1 or MD5
224	uint32				keySizeInBits;
225	uint32				blockSizeInBytes;	// for IV, optional
226	CSSM_PADDING		padding;		// CSSM_PADDING_PKCS7, etc.
227	CSSM_ENCRYPT_MODE	mode;			// CSSM_ALGMODE_CBCPadIV8, etc.
228	PKCS_Which			pkcs;
229
230	bool found = pkcsOidToParams(&algId.algorithm,
231		keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
232		padding, mode, pkcs);
233	if(!found || (pkcs != PW_PKCS12)) {
234		p12ErrorLog("ShroudedKeyBag encrAlg not understood\n");
235		CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
236	}
237
238	uint32 iterCount;
239	if(!p12DataToInt(pbep.iterations, iterCount)) {
240		p12ErrorLog("ShroudedKeyBag: badly formed iterCount\n");
241		P12_THROW_DECODE;
242	}
243	const CSSM_DATA *encrPhrase = getEncrPassPhrase();
244	const CSSM_KEY *passKey = getEncrPassKey();
245	if((encrPhrase == NULL) && (passKey == NULL)) {
246		p12ErrorLog("no passphrase set\n");
247		CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE);
248	}
249
250	/* We'll own the actual CSSM_KEY memory */
251	CSSM_KEY_PTR privKey = (CSSM_KEY_PTR)mCoder.malloc(sizeof(CSSM_KEY));
252	memset(privKey, 0, sizeof(CSSM_KEY));
253
254	CSSM_DATA labelData;
255	p12GenLabel(labelData, localCdr);
256
257	CSSM_RETURN crtn = p12UnwrapKey(mCspHand,
258		mDlDbHand.DLHandle ? &mDlDbHand : NULL,
259		mImportFlags & kSecImportKeys,
260		keyBag->encryptedData,
261		keyAlg, encrAlg, pbeHashAlg,
262		keySizeInBits, blockSizeInBytes,
263		padding, mode,
264		iterCount, pbep.salt,
265		encrPhrase,
266		passKey,
267		localCdr,
268		labelData,
269		mAccess,
270		mNoAcl,
271		mKeyUsage,
272		mKeyAttrs,
273		privKey);
274	if(crtn) {
275		p12ErrorLog("Error unwrapping private key\n");
276		CssmError::throwMe(crtn);
277	}
278	p12DecodeLog("unwrapped shrouded key bag");
279
280	P12KeyBag *p12bag = new P12KeyBag(privKey, mCspHand,
281		safeBag.bagAttrs, labelData, mCoder);
282	addKey(p12bag);
283
284	if(mPrivKeyImportState == PKIS_AllowOne) {
285		mPrivKeyImportState = PKIS_NoMore;
286	}
287}
288
289/*
290 * (unshrouded) KeyBag parser
291 */
292void P12Coder::keyBagParse(
293	const NSS_P12_SafeBag &safeBag,
294	SecNssCoder &localCdr)
295{
296	if(mPrivKeyImportState == PKIS_NoMore) {
297		CssmError::throwMe(errSecMultiplePrivKeys);
298	}
299
300	/* FIXME - should be able to parse and handle this.... */
301	p12DecodeLog("found keyBag");
302	NSS_P12_KeyBag *keyBag = safeBag.bagValue.keyBag;
303	P12OpaqueBag *p12Bag = new P12OpaqueBag(safeBag.bagId,
304		/* this breaks when NSS_P12_KeyBag is not a CSSM_DATA */
305		*keyBag,
306		safeBag.bagAttrs,
307		mCoder);
308	addOpaque(p12Bag);
309}
310
311/*
312 * CertBag parser
313 */
314void P12Coder::certBagParse(
315	const NSS_P12_SafeBag &safeBag,
316	SecNssCoder &localCdr)
317{
318	p12DecodeLog("found certBag");
319	NSS_P12_CertBag *certBag = safeBag.bagValue.certBag;
320	switch(certBag->type) {
321		case CT_X509:
322		case CT_SDSI:
323			break;
324		default:
325			p12ErrorLog("certBagParse: unknown cert type\n");
326			P12_THROW_DECODE;
327	}
328	P12CertBag *p12Bag = new P12CertBag(certBag->type,
329		certBag->certValue,
330		safeBag.bagAttrs,
331		mCoder);
332	addCert(p12Bag);
333}
334
335/*
336 * CrlBag parser
337 */
338void P12Coder::crlBagParse(
339	const NSS_P12_SafeBag &safeBag,
340	SecNssCoder &localCdr)
341{
342	p12DecodeLog("found crlBag");
343	NSS_P12_CrlBag *crlBag = safeBag.bagValue.crlBag;
344	switch(crlBag->type) {
345		case CRT_X509:
346			break;
347		default:
348			p12ErrorLog("crlBagParse: unknown CRL type\n");
349			P12_THROW_DECODE;
350	}
351	P12CrlBag *p12Bag = new P12CrlBag(crlBag->type,
352		crlBag->crlValue,
353		safeBag.bagAttrs,
354		mCoder);
355	addCrl(p12Bag);
356}
357
358/*
359 * SecretBag parser
360 */
361void P12Coder::secretBagParse(
362	const NSS_P12_SafeBag &safeBag,
363	SecNssCoder &localCdr)
364{
365	p12DecodeLog("found secretBag");
366	NSS_P12_SecretBag *secretBag = safeBag.bagValue.secretBag;
367	P12OpaqueBag *p12Bag = new P12OpaqueBag(safeBag.bagId,
368		/* this breaks when NSS_P12_SecretBag is not a CSSM_DATA */
369		*secretBag,
370		safeBag.bagAttrs,
371		mCoder);
372	addOpaque(p12Bag);
373}
374
375/*
376 * SafeContentsBag parser
377 */
378void P12Coder::safeContentsBagParse(
379	const NSS_P12_SafeBag &safeBag,
380	SecNssCoder &localCdr)
381{
382	p12DecodeLog("found SafeContents safe bag");
383	NSS_P12_SafeContentsBag *scBag = safeBag.bagValue.safeContentsBag;
384	P12OpaqueBag *p12Bag = new P12OpaqueBag(safeBag.bagId,
385		/* this breaks when NSS_P12_SafeContentsBag is not a CSSM_DATA */
386		*scBag,
387		safeBag.bagAttrs,
388		mCoder);
389	addOpaque(p12Bag);
390}
391
392/*
393 * Parse an encoded NSS_P12_SafeContents. This could be either
394 * present as plaintext in an AuthSafe or decrypted.
395 */
396void P12Coder::safeContentsParse(
397	const CSSM_DATA &contentsBlob,
398	SecNssCoder &localCdr)
399{
400	p12DecodeLog("safeContentsParse");
401
402	NSS_P12_SafeContents sc;
403	memset(&sc, 0, sizeof(sc));
404	if(localCdr.decodeItem(contentsBlob, NSS_P12_SafeContentsTemplate,
405			&sc)) {
406		p12ErrorLog("Error decoding SafeContents\n");
407		P12_THROW_DECODE;
408	}
409	unsigned numBags = nssArraySize((const void **)sc.bags);
410	for(unsigned dex=0; dex<numBags; dex++) {
411		NSS_P12_SafeBag *bag = sc.bags[dex];
412		assert(bag != NULL);
413
414		/* ensure that *something* is there */
415		if(bag->bagValue.keyBag == NULL) {
416			p12ErrorLog("safeContentsParse: Empty SafeBag\n");
417			P12_THROW_DECODE;
418		}
419
420		/*
421		 * Break out to individual bag type
422		 */
423		switch(bag->type) {
424			case BT_KeyBag:
425				keyBagParse(*bag, localCdr);
426				break;
427			case BT_ShroudedKeyBag:
428				shroudedKeyBagParse(*bag, localCdr);
429				break;
430			case BT_CertBag:
431				certBagParse(*bag, localCdr);
432				break;
433			case BT_CrlBag:
434				crlBagParse(*bag, localCdr);
435				break;
436			case BT_SecretBag:
437				secretBagParse(*bag ,localCdr);
438				break;
439			case BT_SafeContentsBag:
440				safeContentsBagParse(*bag, localCdr);
441				break;
442			default:
443				p12ErrorLog("unknown  p12 BagType (%u)\n",
444					(unsigned)bag->type);
445				P12_THROW_DECODE;
446		}
447	}
448}
449
450/*
451 * Parse a ContentInfo in the context of (i.e., as an element of)
452 * an AuthenticatedSafe.
453 */
454void P12Coder::authSafeElementParse(
455	const NSS_P7_DecodedContentInfo *info,
456	SecNssCoder &localCdr)
457{
458	p12DecodeLog("authSafeElementParse");
459	switch(info->type) {
460		case CT_Data:
461			/* unencrypted SafeContents */
462			safeContentsParse(*info->content.data, localCdr);
463			break;
464
465		case CT_EncryptedData:
466		{
467			NSS_P12_PBE_Params pbep;
468			encryptedDataParse(*info->content.encryptData, localCdr, &pbep);
469
470			/*
471			 * Decrypt contents to get a SafeContents and
472			 * then parse that.
473			 */
474			CSSM_DATA ptext = {0, NULL};
475			encryptedDataDecrypt(*info->content.encryptData,
476				localCdr, &pbep, ptext);
477			safeContentsParse(ptext, localCdr);
478			break;
479		}
480		default:
481			p12ErrorLog("authSafeElementParse: unknown sage type (%u)\n",
482				(unsigned)info->type);
483
484			/* well, save it as an opaque bag for now */
485			P12OpaqueBag *opaque = new P12OpaqueBag(
486				info->contentType, *info->content.data,
487				NULL, 	// no attrs
488				localCdr);
489			addOpaque(opaque);
490			break;
491	}
492}
493
494/*
495 * Parse an encoded NSS_P12_AuthenticatedSafe
496 */
497void P12Coder::authSafeParse(
498	const CSSM_DATA &authSafeBlob,
499	SecNssCoder &localCdr)
500{
501	p12DecodeLog("authSafeParse");
502
503	NSS_P12_AuthenticatedSafe authSafe;
504
505	memset(&authSafe, 0, sizeof(authSafe));
506	if(localCdr.decodeItem(authSafeBlob,
507			NSS_P12_AuthenticatedSafeTemplate,
508			&authSafe)) {
509		p12ErrorLog("Error decoding authSafe\n");
510		P12_THROW_DECODE;
511	}
512	unsigned numInfos = nssArraySize((const void **)authSafe.info);
513	for(unsigned dex=0; dex<numInfos; dex++) {
514		NSS_P7_DecodedContentInfo *info = authSafe.info[dex];
515		authSafeElementParse(info, localCdr);
516	}
517}
518
519void P12Coder::macParse(
520	const NSS_P12_MacData &macData,
521	SecNssCoder &localCdr)
522{
523	p12DecodeLog("macParse");
524	algIdParse(macData.mac.digestAlgorithm, NULL, localCdr);
525	const CSSM_DATA &iter = macData.iterations;
526	if(iter.Length > 4) {
527		p12ErrorLog("malformed iteration length (%u)\n",
528				(unsigned)iter.Length);
529		P12_THROW_DECODE;
530	}
531}
532
533