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 * pkcs12SafeBag.cpp : internal representation of various kinds
25 *                   of P12 SafeBags
26 */
27
28#include "pkcs12SafeBag.h"
29#include "pkcs12Debug.h"
30#include "pkcs12Utils.h"
31#include <string.h>
32#include <assert.h>
33#include <Security/Security.h>
34#include <Security/SecKeyPriv.h>
35#include <Security/SecAsn1Templates.h>
36#include <security_asn1/nssUtils.h>
37
38/*
39 * P12SafeBag, abstract superclass of all safe bags.
40 *
41 * Constructor for decoding. Attr may include friendlyName and localKeyId;
42 * It may also be empty or NULL.
43 */
44P12SafeBag::P12SafeBag(
45	NSS_Attribute 		**attrs, // including friendlyName, etc.
46	SecNssCoder 		&coder)
47	: mBagAttrs(coder),
48	  mCoder(coder)
49{
50	mFriendlyName.Data = mLocalKeyId.Data = NULL;
51	mFriendlyName.Length = mLocalKeyId.Length = 0;
52
53	/* parse attrs into friendlyName, localKeyId, and generic attrs */
54	unsigned numAttrs = nssArraySize((const void **)attrs);
55	for(unsigned dex=0; dex<numAttrs; dex++) {
56		NSS_Attribute *attr = attrs[dex];
57		unsigned numValues = nssArraySize((const void**)attr->attrValue);
58
59		if(nssCompareCssmData(&attr->attrType,
60				&CSSMOID_PKCS9_FriendlyName)) {
61			/*
62			 * BMP string (UniCode). Spec says only one legal value.
63			 */
64			if(numValues != 1) {
65				p12ErrorLog("FriendlyName with %u values\n", numValues);
66				/* but let's keep going if we can */
67				if(numValues == 0) {
68					P12_THROW_DECODE;
69				}
70			}
71			if(mCoder.decodeItem(*attr->attrValue[0],
72					kSecAsn1BMPStringTemplate, &mFriendlyName)) {
73				p12ErrorLog("***Error decoding FriendlyName string\n");
74				P12_THROW_DECODE;
75			}
76		}
77		else if(nssCompareCssmData(&attr->attrType,
78					&CSSMOID_PKCS9_LocalKeyId)) {
79			/*
80			 * Octet string. Spec says only one legal value.
81			 */
82			if(numValues != 1) {
83				p12ErrorLog("LocalKeyId with %u values\n", numValues);
84				/* but let's keep going if we can */
85				if(numValues == 0) {
86					P12_THROW_DECODE;
87				}
88			}
89			if(mCoder.decodeItem(*attr->attrValue[0],
90					kSecAsn1OctetStringTemplate, &mLocalKeyId)) {
91				p12ErrorLog("***Error decoding LocalKeyId\n");
92				P12_THROW_DECODE;
93			}
94		}
95		else {
96			/* others */
97			mBagAttrs.addAttr(*attr);
98		}
99	}
100}
101
102/*
103 * Constructor for encoding. All arguments except for the coder
104 * are optional.
105 */
106P12SafeBag::P12SafeBag(
107	CFStringRef			fname,
108	CFDataRef			keyId,
109	P12BagAttrs			*otherAttrs,		// optional
110	SecNssCoder 		&coder)
111	: mBagAttrs(otherAttrs, coder),
112	  mCoder(coder)
113{
114	friendlyName(fname);
115	localKeyId(keyId);
116}
117
118P12SafeBag::~P12SafeBag()
119{
120	/* nothing if everything we allocd is via mCoder */
121}
122
123/*
124 * Setters in CF terms, used when constructing prior
125 * to encoding.
126 */
127void P12SafeBag::friendlyName(
128	CFStringRef 		fname)
129{
130	CFIndex len = 0;
131
132	if(fname != NULL) {
133		len = CFStringGetLength(fname);
134	}
135	if(len == 0) {
136		mFriendlyName.Data = NULL;
137		mFriendlyName.Length = 0;
138		return;
139	}
140
141	/* convert unicode to byte array */
142	unsigned flen = (unsigned)(len * sizeof(UniChar));
143	mCoder.allocItem(mFriendlyName, flen);
144	unsigned char *cp = mFriendlyName.Data;
145	for(CFIndex dex=0; dex<len; dex++) {
146		UniChar uc = CFStringGetCharacterAtIndex(fname, dex);
147		*cp++ = uc >> 8;
148		*cp++ = uc & 0xff;
149	}
150}
151
152void P12SafeBag::localKeyId(
153	CFDataRef 			keyId)
154{
155	CFIndex len = 0;
156
157	if(keyId != NULL) {
158		len = CFDataGetLength(keyId);
159	}
160	if(len == 0) {
161		mLocalKeyId.Data = NULL;
162		mLocalKeyId.Length = 0;
163		return;
164	}
165	mCoder.allocItem(mLocalKeyId, len);
166	const UInt8 *cp = CFDataGetBytePtr(keyId);
167	memmove(mLocalKeyId.Data, cp, len);
168}
169
170/*
171 * Copy out all attrs in API form. All incoming ptrs
172 * are optional.
173 */
174void P12SafeBag::copyAllAttrs(
175	CFStringRef 		*fName,
176	CFDataRef			*keyId,
177	P12BagAttrs			**bagAttrs)
178{
179	if(fName) {
180		*fName = friendlyName();
181	}
182	if(keyId) {
183		*keyId = localKeyId();
184	}
185	if(bagAttrs) {
186		if(mBagAttrs.numAttrs()) {
187			/* make a copy of our bag attrs */
188			P12BagAttrs *attrs = new P12BagAttrs(&mBagAttrs, mCoder);
189			*bagAttrs = attrs;
190		}
191		else {
192			*bagAttrs = NULL;
193		}
194	}
195}
196
197
198/* getters in CF terms - result is created and returned */
199CFStringRef P12SafeBag::friendlyName()
200{
201	if(mFriendlyName.Data == NULL) {
202		/* not present, no error */
203		return NULL;
204	}
205	/* shouldn't have stored this if it's an odd number of bytes */
206	assert((mFriendlyName.Length & 1) == 0);
207
208	/* convert byte array to unicode */
209	unsigned long strLen = mFriendlyName.Length / 2;
210	UniChar *uc = (UniChar *)malloc(strLen * sizeof(UniChar));
211	const uint8 *inp = mFriendlyName.Data;
212	UniChar *outp = uc;
213	while(inp < (mFriendlyName.Data + mFriendlyName.Length)) {
214		*outp = (((unsigned)inp[0]) << 8) | inp[1];
215		outp++;
216		inp += 2;
217	}
218	CFStringRef cstr = CFStringCreateWithCharacters(NULL, uc, strLen);
219	free(uc);
220	return cstr;
221}
222
223CFDataRef P12SafeBag::localKeyId()
224{
225	if(mLocalKeyId.Data == NULL) {
226		/* not present, no error */
227		return NULL;
228	}
229	return CFDataCreate(NULL, (const UInt8 *)mLocalKeyId.Data,
230		mLocalKeyId.Length);
231}
232
233/*
234 * Get all attrs, including friendlyName and localKeyId,
235 * in preparation for encoding.
236 */
237NSS_Attribute **P12SafeBag::getAllAttrs()
238{
239	unsigned numAttrs = mBagAttrs.numAttrs();
240	if(mFriendlyName.Data) {
241		numAttrs++;
242	}
243	if(mLocalKeyId.Data) {
244		numAttrs++;
245	}
246	NSS_Attribute **attrs =
247		(NSS_Attribute **)p12NssNullArray(numAttrs, mCoder);
248	unsigned outDex=0;
249	for(unsigned i=0; i<mBagAttrs.numAttrs(); i++) {
250		attrs[outDex++] = mBagAttrs.getAttr(i);
251	}
252	if(mFriendlyName.Data) {
253		CSSM_DATA berName = {0, NULL};
254		if(mCoder.encodeItem(&mFriendlyName, kSecAsn1BMPStringTemplate,
255				berName)) {
256			p12ErrorLog("***Error encoding FriendlyName string\n");
257			P12_THROW_ENCODE;
258		}
259		attrs[outDex++] = makeAttr(CSSMOID_PKCS9_FriendlyName,
260			berName);
261	}
262	if(mLocalKeyId.Data) {
263		CSSM_DATA berName = {0, NULL};
264		if(mCoder.encodeItem(&mLocalKeyId, kSecAsn1OctetStringTemplate,
265				berName)) {
266			p12ErrorLog("***Error encoding LocalKeyId string\n");
267			P12_THROW_ENCODE;
268		}
269		attrs[outDex++] = makeAttr(CSSMOID_PKCS9_LocalKeyId,
270			berName);
271	}
272	assert(outDex == numAttrs);
273	return attrs;
274}
275
276/*
277 * Create an NSS_Attribute * for friendlyName or keyId
278 */
279NSS_Attribute *P12SafeBag::makeAttr(
280	const CSSM_OID		&attrId,
281	const CSSM_DATA		&attrValue)
282{
283	NSS_Attribute *attr = mCoder.mallocn<NSS_Attribute>();
284	mCoder.allocCopyItem(attrId, attr->attrType);
285	attr->attrValue = mCoder.mallocn<CSSM_DATA *>(2);
286	attr->attrValue[0] = mCoder.mallocn<CSSM_DATA>();
287	attr->attrValue[1] = NULL;
288	mCoder.allocCopyItem(attrValue, *attr->attrValue[0]);
289	return attr;
290}
291
292/*
293 * Individual bag types
294 */
295
296/* decode */
297P12CertBag::P12CertBag(
298	NSS_P12_CertBagType	certType,	// CT_X509, CT_SDSI
299	CSSM_DATA			&certData,
300	NSS_Attribute		**attrs,	// optional
301	SecNssCoder			&coder)
302		: P12SafeBag(attrs, coder),
303		  mCertType(certType),
304		  mCertRef(NULL)
305{
306	coder.allocCopyItem(certData, mCertData);
307}
308
309/* encode */
310P12CertBag::P12CertBag(
311	NSS_P12_CertBagType	certType,	// CT_X509, CT_SDSI
312	CSSM_DATA			&certData,
313	CFStringRef			fname,
314	CFDataRef			keyId,
315	P12BagAttrs			*otherAttrs,
316	SecNssCoder			&coder)
317		: P12SafeBag(fname, keyId, otherAttrs, coder),
318		  mCertType(certType),
319		  mCertRef(NULL)
320{
321	coder.allocCopyItem(certData, mCertData);
322}
323
324P12CertBag::~P12CertBag()
325{
326	if(mCertRef) {
327		CFRelease(mCertRef);
328	}
329	/* everything else we allocd is via mCoder */
330}
331
332/* convert to P12CertBag to SecCertificateRef */
333SecCertificateRef P12CertBag::getSecCert()
334{
335	if(mCertRef) {
336		CFRetain(mCertRef);		/* a ref count for the caller */
337		return mCertRef;
338	}
339
340	/* lazy creation... */
341	CSSM_CERT_TYPE certType;
342	CSSM_CERT_ENCODING certEncoding;
343	switch(mCertType) {
344		case CT_X509:
345			certType = CSSM_CERT_X_509v3;
346			certEncoding = CSSM_CERT_ENCODING_DER;
347			break;
348		case CT_SDSI:
349			certType = CSSM_CERT_SDSIv1;
350			/* it's base64 encoded - no value for that in this enum */
351			certEncoding = CSSM_CERT_ENCODING_UNKNOWN;
352			break;
353		default:
354			/* shouldn't currently happen, but... */
355			certType = CSSM_CERT_UNKNOWN;
356			certEncoding = CSSM_CERT_ENCODING_UNKNOWN;
357			break;
358	}
359	OSStatus ortn = SecCertificateCreateFromData(
360		&mCertData,
361		certType,
362		certEncoding,
363		&mCertRef);
364	if(ortn) {
365		MacOSError::throwMe(ortn);
366	}
367
368	/* One ref count for us, one for the caller */
369	CFRetain(mCertRef);
370	return mCertRef;
371}
372
373P12CrlBag::P12CrlBag(
374	NSS_P12_CrlBagType	crlType,	// CRT_X509, only for now
375	CSSM_DATA			&crlData,
376	NSS_Attribute		**attrs,	// optional
377	SecNssCoder			&coder)
378		: P12SafeBag(attrs, coder),
379		  mCrlType(crlType)
380{
381	coder.allocCopyItem(crlData, mCrlData);
382}
383
384P12CrlBag::P12CrlBag(
385	NSS_P12_CrlBagType	crlType,	// CRT_X509, only for now
386	CFDataRef			crlData,
387	CFStringRef			fname,
388	CFDataRef			keyId,
389	P12BagAttrs			*otherAttrs,
390	SecNssCoder			&coder)
391		: P12SafeBag(fname, keyId, otherAttrs, coder),
392		  mCrlType(crlType)
393{
394	coder.allocCopyItem(CFDataGetBytePtr(crlData),
395		CFDataGetLength(crlData), mCrlData);
396}
397
398P12CrlBag::~P12CrlBag()
399{
400	/* nothing if everything we allocd is via mCoder */
401}
402
403/*
404 * For decode - both shrouded and plain.
405 * On decode, we own the key and will do the CSSM_FreeKey in
406 * our destructor. Caller owns the actual CSSM_KEY memory.
407 */
408P12KeyBag::P12KeyBag(
409	CSSM_KEY_PTR		key,
410	CSSM_CSP_HANDLE		cspHand,
411	NSS_Attribute		**attrs,	// optional
412	CSSM_DATA			&labelData,
413	SecNssCoder			&coder)
414		: P12SafeBag(attrs, coder),
415		  mKey(key),
416		  mCspHand(cspHand),
417		  mKeyRef(NULL),
418		  mWeOwnKey(true),
419		  mPrivKeyCreds(NULL),
420		  mDupKey(false)
421{
422	setLabel(labelData);
423}
424
425/* for encode - app owns CSSM_KEY */
426P12KeyBag::P12KeyBag(
427	const CSSM_KEY		*key,
428	CSSM_CSP_HANDLE		cspHand,
429	CFStringRef			fname,
430	CFDataRef			keyId,
431	P12BagAttrs			*otherAttrs,
432	SecNssCoder			&coder,
433	SecKeyRef			keyRef /* = NULL */)
434
435		: P12SafeBag(fname, keyId, otherAttrs, coder),
436		  mKey((CSSM_KEY_PTR)key),
437		  mCspHand(cspHand),
438		  mKeyRef(keyRef),
439		  mWeOwnKey(false),		// app giveth, app taketh away
440		  mPrivKeyCreds(NULL),
441		  mDupKey(false)
442{
443	if(mKeyRef) {
444		CFRetain(mKeyRef);
445		/*
446	 	 * Get creds associated with this key
447		 */
448		OSStatus ortn = SecKeyGetCredentials(mKeyRef,
449			CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
450			kSecCredentialTypeDefault,
451			&mPrivKeyCreds);
452		if(ortn) {
453			p12LogCssmError("SecKeyGetCredentials", ortn);
454			MacOSError::throwMe(ortn);
455		}
456	}
457	mLabel.Data = NULL;
458	mLabel.Length = 0;
459}
460
461
462P12KeyBag::~P12KeyBag()
463{
464	freeKey();
465}
466
467void P12KeyBag::setLabel(
468	const CSSM_DATA &newLabel)
469{
470	mCoder.allocCopyItem(newLabel, mLabel);
471}
472
473/* reusable key setter */
474void P12KeyBag::setKey(
475	CSSM_KEY_PTR cssmKey)
476{
477	freeKey();
478	mKey = cssmKey;
479}
480
481void P12KeyBag::freeKey()
482{
483	if(mWeOwnKey) {
484		assert(mKey != NULL);
485		assert(mCspHand != 0);
486		CSSM_FreeKey(mCspHand, NULL, mKey, CSSM_FALSE);
487	}
488	mKey = NULL;
489	if(mKeyRef) {
490		CFRelease(mKeyRef);
491		mKeyRef = NULL;
492	}
493}
494
495/*
496 * Others we don't implement
497 */
498P12OpaqueBag::P12OpaqueBag(
499	const CSSM_OID		&oid,
500	const CSSM_DATA		&blob,
501	NSS_Attribute		**attrs,	// optional
502	SecNssCoder			&coder)
503		: P12SafeBag(attrs, coder)
504{
505	coder.allocCopyItem(oid, mOid);
506	coder.allocCopyItem(blob, mBlob);
507}
508
509P12OpaqueBag::P12OpaqueBag(
510	CFDataRef			oid,
511	CFDataRef			blob,
512	CFStringRef			fname,
513	CFDataRef			keyId,
514	P12BagAttrs			*otherAttrs,
515	SecNssCoder			&coder)
516		: P12SafeBag(fname, keyId, otherAttrs, coder)
517{
518	coder.allocCopyItem(CFDataGetBytePtr(oid),
519		CFDataGetLength(oid), mOid);
520	coder.allocCopyItem(CFDataGetBytePtr(blob),
521		CFDataGetLength(blob), mBlob);
522}
523
524P12OpaqueBag::~P12OpaqueBag()
525{
526	/* nothing if everything we allocd is via mCoder */
527}
528
529