1/*
2 * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18/*
19 * clNssUtils.cpp - support for libnssasn1-based ASN1 encode/decode
20 */
21
22#include "clNssUtils.h"
23#include "clNameUtils.h"
24#include "CSPAttacher.h"
25#include <security_asn1/secasn1.h>
26#include <security_asn1/SecNssCoder.h>
27#include <security_asn1/nssUtils.h>
28#include <Security/keyTemplates.h>
29#include <Security/certExtensionTemplates.h>
30#include <Security/oidsalg.h>
31#include <Security/oidsattr.h>
32#include <Security/cssmapple.h>
33#include <string.h>
34
35#pragma mark ----- ArenaAllocator -----
36
37/*
38 * Avoid inlining this for debuggability
39 */
40void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc)
41{
42	try {
43		return mCoder.malloc(len);
44	}
45	catch (...) {
46		throw std::bad_alloc();
47	}
48}
49
50/* intentionally not implemented, should never be called */
51void ArenaAllocator::free(void *p) throw()
52{
53	throw std::bad_alloc();
54}
55
56void *ArenaAllocator::realloc(void *p, size_t len) throw(std::bad_alloc)
57{
58	throw std::bad_alloc();
59}
60
61#pragma mark ----- Malloc/Copy/Compare CSSM_DATA -----
62
63/*
64 * Misc. alloc/copy with arbitrary Allocator
65 */
66/* malloc d.Data, set d.Length */
67void clAllocData(
68	Allocator	&alloc,
69	CSSM_DATA		&dst,
70	size_t			len)
71{
72	if(len == 0) {
73		dst.Data = NULL;
74	}
75	else {
76		dst.Data = (uint8 *)alloc.malloc(len);
77	}
78	dst.Length = len;
79}
80
81/* malloc and copy */
82void clAllocCopyData(
83	Allocator	&alloc,
84	const CSSM_DATA	&src,
85	CSSM_DATA		&dst)
86{
87	clAllocData(alloc, dst, src.Length);
88	if(dst.Length != 0) {
89		memmove(dst.Data, src.Data, src.Length);
90	}
91}
92
93/*
94 * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical.
95 */
96bool clCompareCssmData(
97	const CSSM_DATA *data1,
98	const CSSM_DATA *data2)
99{
100	if((data1 == NULL) || (data1->Data == NULL) ||
101	   (data2 == NULL) || (data2->Data == NULL) ||
102	   (data1->Length != data2->Length)) {
103		return false;
104	}
105	if(data1->Length != data2->Length) {
106		return false;
107	}
108	if(memcmp(data1->Data, data2->Data, data1->Length) == 0) {
109		return true;
110	}
111	else {
112		return false;
113	}
114}
115
116#pragma mark ----- CSSM_DATA <--> uint32 -----
117
118uint32 clDataToInt(
119	const CSSM_DATA &cdata,
120	CSSM_RETURN toThrow)	/* = CSSMERR_CL_INVALID_CERT_POINTER */
121{
122	if((cdata.Length == 0) || (cdata.Data == NULL)) {
123		return 0;
124	}
125	size_t len = cdata.Length;
126	if(len > sizeof(uint32)) {
127		if(toThrow == 0) {
128			/* tolerate this */
129			len = sizeof(uint32);
130		}
131		else {
132			CssmError::throwMe(toThrow);
133		}
134	}
135
136	uint32 rtn = 0;
137	uint8 *cp = cdata.Data;
138	for(size_t i=0; i<len; i++) {
139		rtn = (rtn << 8) | *cp++;
140	}
141	return rtn;
142}
143
144void clIntToData(
145	uint32 num,
146	CSSM_DATA &cdata,
147	Allocator &alloc)
148{
149	uint32 len = 0;
150
151	if(num < 0x100) {
152		len = 1;
153	}
154	else if(num < 0x10000) {
155		len = 2;
156	}
157	else if(num < 0x1000000) {
158		len = 3;
159	}
160	else {
161		len = 4;
162	}
163	clAllocData(alloc, cdata, len);
164	uint8 *cp = &cdata.Data[len - 1];
165	for(unsigned i=0; i<len; i++) {
166		*cp-- = num & 0xff;
167		num >>= 8;
168	}
169}
170
171#pragma mark ----- CSSM_BOOL <--> CSSM_DATA -----
172/*
173 * A Bool is encoded as one byte of either 0 or 0xff
174 * Default of NSS boolean not present is false
175 */
176CSSM_BOOL clNssBoolToCssm(
177	const CSSM_DATA	&nssBool)
178{
179	if((nssBool.Data != NULL) && (nssBool.Data[0] == 0xff)) {
180		return CSSM_TRUE;
181	}
182	else {
183		return CSSM_FALSE;
184	}
185}
186
187void clCssmBoolToNss(
188	CSSM_BOOL cBool,
189	CSSM_DATA &nssBool,
190	Allocator &alloc)
191{
192	uint32 num = cBool ? 0xff : 0;
193	clIntToData(num, nssBool, alloc);
194}
195
196#pragma mark ----- Bit String manipulation -----
197
198/*
199 * Adjust the length of a CSSM_DATA representing a pre-encoded
200 * bit string. On entry the length field is the number of bytes
201 * of data; en exit, the number if bits. Trailing zero bits
202 * are counted as unused (which is how KeyUsage and NetscapeCertType
203 * extensions are encoded).
204 */
205void clCssmBitStringToNss(
206	CSSM_DATA &b)
207{
208	size_t numBits = b.Length * 8;
209
210	/* start at end of bit array, scanning backwards looking
211	 * for the first set bit */
212	bool foundSet = false;
213	for(ptrdiff_t dex=b.Length-1; dex>=0; dex--) {
214		unsigned bitMask = 0x01;
215		uint8 byte = b.Data[dex];
216		for(unsigned bdex=0; bdex<8; bdex++) {
217			if(byte & bitMask) {
218				foundSet = true;
219				break;
220			}
221			else {
222				bitMask <<= 1;
223				numBits--;
224			}
225		}
226		if(foundSet) {
227			break;
228		}
229	}
230	/* !foundSet --> numBits = 0 */
231	assert(((numBits > 0) & foundSet) || ((numBits == 0) && !foundSet));
232	b.Length = numBits;
233}
234
235/*
236 * On entry, Length is bit count; on exit, a byte count.
237 * The job here is to ensure that bits marked as "unused" in the
238 * BER encoding are cleared. Encoding rules say they are undefined in
239 * the actual encoding.
240 */
241void clNssBitStringToCssm(
242	CSSM_DATA &b)
243{
244	CSSM_SIZE byteCount = (b.Length + 7) / 8;
245	unsigned partialBits = b.Length & 0x7;
246	b.Length = byteCount;
247	if(partialBits == 0) {
248		return;
249	}
250
251	/* mask off unused bits */
252	unsigned unusedBits = 8 - partialBits;
253	uint8 *bp = b.Data + b.Length - 1;
254	/* mask = (2 ** unusedBits) - 1 */
255	unsigned mask = (1 << unusedBits) - 1;
256	*bp &= ~mask;
257}
258
259#pragma mark ----- NSS array manipulation -----
260/*
261 * How many items in a NULL-terminated array of pointers?
262 */
263unsigned clNssArraySize(
264	const void **array)
265{
266    unsigned count = 0;
267    if (array) {
268		while (*array++) {
269			count++;
270		}
271    }
272    return count;
273}
274
275/* malloc a NULL-ed array of pointers of size num+1 */
276void **clNssNullArray(
277	uint32 num,
278	SecNssCoder &coder)
279{
280	unsigned len = (num + 1) * sizeof(void *);
281	void **p = (void **)coder.malloc(len);
282	memset(p, 0, len);
283	return p;
284}
285
286/*
287 * GIven a CSSM_DATA containing a decoded BIT_STRING,
288 * convert to a KeyUsage.
289 */
290CE_KeyUsage clBitStringToKeyUsage(
291	const CSSM_DATA &cdata)
292{
293	size_t toCopy = (cdata.Length + 7) / 8;
294	if(toCopy > 2) {
295		/* I hope I never see this... */
296		clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!");
297		toCopy = 2;
298	}
299	unsigned char bits[2] = {0, 0};
300	memmove(bits, cdata.Data, toCopy);
301	CE_KeyUsage usage = (((unsigned)bits[0]) << 8) | bits[1];
302	return usage;
303}
304
305CSSM_ALGORITHMS CL_oidToAlg(
306	const CSSM_OID &oid)
307{
308	CSSM_ALGORITHMS alg;
309	bool found = cssmOidToAlg(&oid, &alg);
310	if(!found) {
311		clErrorLog("CL_oidToAlg: unknown alg\n");
312		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
313	}
314	return alg;
315}
316
317#pragma mark ----- copy CSSM_X509_ALGORITHM_IDENTIFIER -----
318
319/*
320 * Copy CSSM_X509_ALGORITHM_IDENTIFIER, same format (NSS and CSSM).
321 */
322void CL_copyAlgId(
323	const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId,
324	CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId,
325	Allocator &alloc)
326{
327	clAllocCopyData(alloc, srcAlgId.algorithm, dstAlgId.algorithm);
328	clAllocCopyData(alloc, srcAlgId.parameters, dstAlgId.parameters);
329}
330
331void CL_freeCssmAlgId(
332	CSSM_X509_ALGORITHM_IDENTIFIER	*cdsaObj,		// optional
333	Allocator 					&alloc)
334{
335	if(cdsaObj == NULL) {
336		return;
337	}
338	alloc.free(cdsaObj->algorithm.Data);
339	alloc.free(cdsaObj->parameters.Data);
340	memset(cdsaObj, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
341}
342
343
344#pragma mark ----- CSSM_X509_TIME <--> NSS format -----
345
346/*
347 * Map the tag associated with a choice of DirectoryString elements to
348 * a template array for encoding/decoding that string type.
349 * Contrary to RFC2459, we allow the IA5String type, which is actually
350 * used in the real world (cf. the email address in Thawte's serverbasic
351 * cert).
352 */
353
354/* The template chooser does the work here */
355
356bool CL_nssTimeToCssm(
357	const NSS_TaggedItem 	&nssTime,
358	CSSM_X509_TIME			&cssmObj,
359	Allocator 			&alloc)
360{
361	cssmObj.timeType = nssTime.tag;
362	clAllocCopyData(alloc, nssTime.item, cssmObj.time);
363	return true;
364}
365
366/*
367 * CSSM time to NSS time.
368 */
369void CL_cssmTimeToNss(
370	const CSSM_X509_TIME &cssmTime,
371	NSS_TaggedItem &nssTime,
372	SecNssCoder &coder)
373{
374	nssTime.tag = cssmTime.timeType;
375	coder.allocCopyItem(cssmTime.time, nssTime.item);
376}
377
378void CL_freeCssmTime(
379	CSSM_X509_TIME	*cssmTime,
380	Allocator	&alloc)
381{
382	if(cssmTime == NULL) {
383		return;
384	}
385	if(cssmTime->time.Data) {
386		alloc.free(cssmTime->time.Data);
387	}
388	memset(cssmTime, 0, sizeof(CSSM_X509_TIME));
389}
390
391
392#pragma mark ----- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO <--> CSSM_KEY  -----
393
394/*
395 * Copy a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO.
396 *
397 * Same format (NSS and CSSM), EXCEPT:
398 *
399 *   Objects which have just been NSS decoded or are about to be
400 *   NSS encoded have the subjectPublicKey.Length field in BITS
401 *   since this field is wrapped in a BIT STRING upon encoding.
402 *
403 *   Caller tells us which format (bits or bytes)
404 *   to use for each of {src, dst}.
405 */
406void CL_copySubjPubKeyInfo(
407	const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo,
408	bool srcInBits,
409	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstInfo,
410	bool dstInBits,
411	Allocator &alloc)
412{
413	CL_copyAlgId(srcInfo.algorithm, dstInfo.algorithm, alloc);
414
415	CSSM_DATA srcKey = srcInfo.subjectPublicKey;
416	if(srcInBits) {
417		srcKey.Length = (srcKey.Length + 7) / 8;
418	}
419	clAllocCopyData(alloc, srcKey, dstInfo.subjectPublicKey);
420	if(dstInBits) {
421		dstInfo.subjectPublicKey.Length *= 8;
422	}
423}
424
425/*
426 * Obtain a CSSM_KEY from a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO,
427 * inferring as much as we can from required fields
428 * (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) and extensions (for
429 * KeyUse, obtained from the optional DecodedCert).
430 */
431CSSM_KEY_PTR CL_extractCSSMKeyNSS(
432	const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO	&keyInfo,
433	Allocator			&alloc,
434	const DecodedCert		*decodedCert)			// optional
435{
436	CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY));
437	memset(cssmKey, 0, sizeof(CSSM_KEY));
438	CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
439	CssmRemoteData keyData(alloc, cssmKey->KeyData);
440
441	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
442	/* CspId blank */
443	hdr.BlobType = CSSM_KEYBLOB_RAW;
444	hdr.AlgorithmId = CL_oidToAlg(keyInfo.algorithm.algorithm);
445	hdr.KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
446
447	/*
448	 * Format inferred from AlgorithmId. I have never seen these defined
449	 * anywhere, e.g., what's the format of an RSA public key in a cert?
450	 * X509 certainly doesn't say. However. the following two cases are
451	 * known to be correct.
452	 */
453	switch(hdr.AlgorithmId) {
454		case CSSM_ALGID_RSA:
455			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
456			break;
457		case CSSM_ALGID_DSA:
458		case CSSM_ALGID_ECDSA:
459		case CSSM_ALGID_DH:
460		case CSSM_ALGMODE_PKCS1_EME_OAEP:
461			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_X509;
462			break;
463		case CSSM_ALGID_FEE:
464			/* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
465			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
466			break;
467		default:
468			/* punt */
469			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
470	}
471	hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
472
473	/* KeyUsage inferred from extensions */
474	if(decodedCert) {
475		hdr.KeyUsage = decodedCert->inferKeyUsage();
476	}
477	else {
478		hdr.KeyUsage = CSSM_KEYUSE_ANY;
479	}
480
481	/* start/end date unknown, leave zero */
482	hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
483	hdr.WrapMode = CSSM_ALGMODE_NONE;
484
485	switch(hdr.AlgorithmId) {
486		case CSSM_ALGID_DSA:
487		case CSSM_ALGID_ECDSA:
488		case CSSM_ALGID_DH:
489		case CSSM_ALGMODE_PKCS1_EME_OAEP:
490		{
491			/*
492			 * Just encode the whole subject public key info blob.
493			 * NOTE we're assuming that the keyInfo.subjectPublicKey
494			 * field is in the NSS_native BITSTRING format, i.e.,
495			 * its Length field is in bits and we don't have to adjust.
496			 */
497			PRErrorCode prtn = SecNssEncodeItemOdata(&keyInfo,
498				kSecAsn1SubjectPublicKeyInfoTemplate, keyData);
499			if(prtn) {
500				clErrorLog("extractCSSMKey: error on reencode\n");
501				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
502			}
503			break;
504		}
505		default:
506			/*
507			 * RSA, FEE for now.
508			 * keyInfo.subjectPublicKey (in BITS) ==> KeyData
509			 */
510			keyData.copy(keyInfo.subjectPublicKey.Data,
511				(keyInfo.subjectPublicKey.Length + 7) / 8);
512	}
513
514	/*
515	 * LogicalKeySizeInBits - ask the CSP
516	 */
517	CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
518	CSSM_KEY_SIZE keySize;
519	CSSM_RETURN crtn;
520	crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, cssmKey,
521		&keySize);
522	switch(crtn) {
523		default:
524			CssmError::throwMe(crtn);
525		case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE:
526			/*
527			 * This is how the CSP indicates a "partial" public key,
528			 * with a valid public key value but no alg-specific
529			 * parameters (currently, DSA only).
530			 */
531			hdr.KeyAttr |= CSSM_KEYATTR_PARTIAL;
532			/* and drop thru */
533		case CSSM_OK:
534			cssmKey->KeyHeader.LogicalKeySizeInBits =
535				keySize.LogicalKeySizeInBits;
536			break;
537	}
538
539	keyData.release();
540	return cssmKey;
541}
542
543/*
544 * Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters.
545 */
546void CL_nullAlgParams(
547	CSSM_X509_ALGORITHM_IDENTIFIER	&algId)
548{
549	static const uint8 encNull[2] = { SEC_ASN1_NULL, 0 };
550	CSSM_DATA encNullData;
551	encNullData.Data = (uint8 *)encNull;
552	encNullData.Length = 2;
553
554	algId.parameters = encNullData;
555}
556
557/*
558 * Convert a CSSM_KEY to a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. The
559 * CSSM key must be in raw format and with a specific blob format.
560 *  	-- RSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_PKCS1
561 * 		-- DSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
562 * 		-- ECDSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
563 */
564void CL_CSSMKeyToSubjPubKeyInfoNSS(
565	const CSSM_KEY 						&cssmKey,
566	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO	&nssKeyInfo,
567	SecNssCoder							&coder)
568{
569	const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
570	if(hdr.BlobType != CSSM_KEYBLOB_RAW) {
571		clErrorLog("CL SetField: must specify RAW key blob\n");
572		CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
573	}
574	memset(&nssKeyInfo, 0, sizeof(nssKeyInfo));
575
576	/* algorithm and format dependent from here... */
577	switch(hdr.AlgorithmId) {
578		case CSSM_ALGID_RSA:
579			if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
580				clErrorLog("CL SetField: RSA key must be in PKCS1 format\n");
581				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
582			}
583			/* and fall thru */
584		default:
585		{
586			/* Key header's algorithm --> OID */
587			const CSSM_OID *oid = cssmAlgToOid(hdr.AlgorithmId);
588			if(oid == NULL) {
589				clErrorLog("CL SetField: Unknown key algorithm\n");
590				CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
591			}
592			CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssKeyInfo.algorithm;
593			coder.allocCopyItem(*oid, algId.algorithm);
594
595			/* NULL algorithm parameters, always in this case */
596			CL_nullAlgParams(algId);
597
598			/* Copy key bits, destination is a BIT STRING */
599			coder.allocCopyItem(cssmKey.KeyData, nssKeyInfo.subjectPublicKey);
600			nssKeyInfo.subjectPublicKey.Length *= 8;
601			break;
602		}
603		case CSSM_ALGID_DSA:
604		case CSSM_ALGID_ECDSA:
605			if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_X509) {
606				clErrorLog("CL SetField: DSA/ECDSA key must be in X509 format\n");
607				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
608			}
609
610			/*
611			 * All we do is decode the whole key blob into the
612			 * SubjectPublicKeyInfo.
613			 */
614			if(coder.decodeItem(cssmKey.KeyData,
615					kSecAsn1SubjectPublicKeyInfoTemplate,
616					&nssKeyInfo)) {
617				clErrorLog("CL SetField: Error decoding DSA public key\n");
618				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
619			}
620			break;
621	}
622}
623
624void CL_freeCSSMKey(
625	CSSM_KEY_PTR		cssmKey,
626	Allocator		&alloc,
627	bool				freeTop)
628{
629	if(cssmKey == NULL) {
630		return;
631	}
632	alloc.free(cssmKey->KeyData.Data);
633	memset(cssmKey, 0, sizeof(CSSM_KEY));
634	if(freeTop) {
635		alloc.free(cssmKey);
636	}
637}
638
639#pragma mark ----- CE_AuthorityKeyID <--> NSS_AuthorityKeyId -----
640
641void CL_cssmAuthorityKeyIdToNss(
642	const CE_AuthorityKeyID 	&cdsaObj,
643	NSS_AuthorityKeyId 			&nssObj,
644	SecNssCoder 				&coder)
645{
646	memset(&nssObj, 0, sizeof(nssObj));
647	if(cdsaObj.keyIdentifierPresent) {
648		nssObj.keyIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
649		coder.allocCopyItem(cdsaObj.keyIdentifier, *nssObj.keyIdentifier);
650	}
651	if(cdsaObj.generalNamesPresent ) {
652		/* GeneralNames, the hard one */
653		CL_cssmGeneralNamesToNss(*cdsaObj.generalNames,
654			nssObj.genNames, coder);
655	}
656	if(cdsaObj.serialNumberPresent) {
657		coder.allocCopyItem(cdsaObj.serialNumber,nssObj.serialNumber);
658	}
659}
660
661void CL_nssAuthorityKeyIdToCssm(
662	const NSS_AuthorityKeyId 		&nssObj,
663	CE_AuthorityKeyID 				&cdsaObj,
664	SecNssCoder 					&coder,	// for temp decoding
665	Allocator					&alloc)
666{
667	if(nssObj.keyIdentifier != NULL) {
668		cdsaObj.keyIdentifierPresent = CSSM_TRUE;
669		clAllocCopyData(alloc, *nssObj.keyIdentifier, cdsaObj.keyIdentifier);
670	}
671	if(nssObj.genNames.names != NULL) {
672		/* GeneralNames, the hard one */
673		cdsaObj.generalNamesPresent = CSSM_TRUE;
674		cdsaObj.generalNames =
675			(CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames));
676		CL_nssGeneralNamesToCssm(nssObj.genNames,
677			*cdsaObj.generalNames,
678			coder,
679			alloc);
680	}
681	if(nssObj.serialNumber.Data != NULL) {
682		cdsaObj.serialNumberPresent = CSSM_TRUE;
683		clAllocCopyData(alloc, nssObj.serialNumber, cdsaObj.serialNumber);
684	}
685}
686
687#pragma mark ----- CE_AuthorityInfoAccess <--> NSS_AuthorityInfoAccess -----
688
689void CL_cssmInfoAccessToNss(
690	const CE_AuthorityInfoAccess	&cdsaObj,
691	NSS_AuthorityInfoAccess			&nssObj,
692	SecNssCoder						&coder)
693{
694	memset(&nssObj, 0, sizeof(nssObj));
695	uint32 numDescs = cdsaObj.numAccessDescriptions;
696	nssObj.accessDescriptions = (NSS_AccessDescription **)clNssNullArray(numDescs, coder);
697
698	for(unsigned dex=0; dex<numDescs; dex++) {
699		nssObj.accessDescriptions[dex] = coder.mallocn<NSS_AccessDescription>();
700		CE_AccessDescription *src = &cdsaObj.accessDescriptions[dex];
701		NSS_AccessDescription *dst = nssObj.accessDescriptions[dex];
702		coder.allocCopyItem(src->accessMethod, dst->accessMethod);
703
704		/* Convert general name, then encode it into destination */
705		NSS_GeneralName nssGenName;
706		CL_cssmGeneralNameToNss(src->accessLocation, nssGenName, coder);
707		PRErrorCode prtn = coder.encodeItem(&nssGenName, kSecAsn1GeneralNameTemplate,
708			dst->encodedAccessLocation);
709		if(prtn) {
710			clErrorLog("CL_cssmInfoAccessToNss: encode error\n");
711			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
712		}
713	}
714}
715
716void CL_infoAccessToCssm(
717	const NSS_AuthorityInfoAccess 	&nssObj,
718	CE_AuthorityInfoAccess			&cdsaObj,
719	SecNssCoder						&coder,	// for temp decoding
720	Allocator						&alloc)
721{
722	memset(&cdsaObj, 0, sizeof(cdsaObj));
723	unsigned numDescs = clNssArraySize((const void **)nssObj.accessDescriptions);
724	if(numDescs == 0) {
725		return;
726	}
727	cdsaObj.accessDescriptions = (CE_AccessDescription *)alloc.malloc(
728		numDescs * sizeof(CE_AccessDescription));
729	cdsaObj.numAccessDescriptions = numDescs;
730	for(unsigned dex=0; dex<numDescs; dex++) {
731		CE_AccessDescription *dst = &cdsaObj.accessDescriptions[dex];
732		NSS_AccessDescription *src = nssObj.accessDescriptions[dex];
733		clAllocCopyData(alloc, src->accessMethod, dst->accessMethod);
734
735		/* decode the general name */
736		NSS_GeneralName nssGenName;
737		memset(&nssGenName, 0, sizeof(nssGenName));
738		PRErrorCode prtn = coder.decodeItem(src->encodedAccessLocation,
739			kSecAsn1GeneralNameTemplate, &nssGenName);
740		if(prtn) {
741			clErrorLog("***Error decoding NSS_AuthorityInfoAccess.accessLocation\n");
742			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
743		}
744
745		/* then convert the result to CSSM */
746		CL_nssGeneralNameToCssm(nssGenName, dst->accessLocation, coder, alloc);
747	}
748}
749
750void CL_freeInfoAccess(
751	CE_AuthorityInfoAccess	&cssmInfo,
752	Allocator				&alloc)
753{
754	uint32 numDescs = cssmInfo.numAccessDescriptions;
755	for(unsigned dex=0; dex<numDescs; dex++) {
756		CE_AccessDescription *dst = &cssmInfo.accessDescriptions[dex];
757		alloc.free(dst->accessMethod.Data);
758		CL_freeCssmGeneralName(dst->accessLocation, alloc);
759	}
760	alloc.free(cssmInfo.accessDescriptions);
761}
762
763
764#pragma mark ----- CE_QC_Statements <--> NSS_QC_Statements -----
765
766void CL_cssmQualCertStatementsToNss(
767	const CE_QC_Statements	 	&cdsaObj,
768	NSS_QC_Statements 			&nssObj,
769	SecNssCoder 				&coder)
770{
771	memset(&nssObj, 0, sizeof(nssObj));
772	uint32 numQcs = cdsaObj.numQCStatements;
773	nssObj.qcStatements =
774		(NSS_QC_Statement **)clNssNullArray(numQcs, coder);
775	for(uint32 dex=0; dex<numQcs; dex++) {
776		nssObj.qcStatements[dex] = (NSS_QC_Statement *)
777			coder.malloc(sizeof(NSS_QC_Statement));
778		NSS_QC_Statement *dst = nssObj.qcStatements[dex];
779		CE_QC_Statement *src = &cdsaObj.qcStatements[dex];
780		memset(dst, 0, sizeof(*dst));
781		coder.allocCopyItem(src->statementId, dst->statementId);
782		if(src->semanticsInfo) {
783			if(src->otherInfo) {
784				/* this is either/or, not both */
785				CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
786			}
787
788			/* encode this CE_SemanticsInformation */
789			CE_SemanticsInformation *srcSI = src->semanticsInfo;
790			NSS_SemanticsInformation dstSI;
791			memset(&dstSI, 0, sizeof(dstSI));
792			if(srcSI->semanticsIdentifier) {
793				dstSI.semanticsIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
794				coder.allocCopyItem(*srcSI->semanticsIdentifier,
795					*dstSI.semanticsIdentifier);
796			}
797			if(srcSI->nameRegistrationAuthorities) {
798				dstSI.nameRegistrationAuthorities =
799					(NSS_GeneralNames *)coder.malloc(sizeof(NSS_GeneralNames));
800				CL_cssmGeneralNamesToNss(*srcSI->nameRegistrationAuthorities,
801					*dstSI.nameRegistrationAuthorities, coder);
802			}
803			PRErrorCode prtn = coder.encodeItem(&dstSI, kSecAsn1SemanticsInformationTemplate,
804				dst->info);
805			if(prtn) {
806				clErrorLog("CL_cssmQualCertStatementsToNss: encode error\n");
807				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
808			}
809
810		}
811		if(src->otherInfo) {
812			/* drop in as ASN_ANY */
813			coder.allocCopyItem(*src->otherInfo, dst->info);
814		}
815	}
816}
817
818void CL_qualCertStatementsToCssm(
819	const NSS_QC_Statements 		&nssObj,
820	CE_QC_Statements 				&cdsaObj,
821	SecNssCoder 					&coder,	// for temp decoding
822	Allocator						&alloc)
823{
824	memset(&cdsaObj, 0, sizeof(cdsaObj));
825	unsigned numQcs = clNssArraySize((const void **)nssObj.qcStatements);
826	if(numQcs == 0) {
827		return;
828	}
829	cdsaObj.qcStatements = (CE_QC_Statement *)alloc.malloc(
830		numQcs * sizeof(CE_AccessDescription));
831	cdsaObj.numQCStatements = numQcs;
832	for(unsigned dex=0; dex<numQcs; dex++) {
833		CE_QC_Statement *dst = &cdsaObj.qcStatements[dex];
834		NSS_QC_Statement *src = nssObj.qcStatements[dex];
835
836		memset(dst, 0, sizeof(*dst));
837		clAllocCopyData(alloc, src->statementId, dst->statementId);
838
839		/*
840		 * Whether the optional info is a SemanticsInformation or is uninterpreted
841 		 * DER data depends on statementId.
842		 */
843		if(src->info.Data) {
844			if(clCompareCssmData(&src->statementId, &CSSMOID_OID_QCS_SYNTAX_V2)) {
845				NSS_SemanticsInformation srcSI;
846				memset(&srcSI, 0, sizeof(srcSI));
847
848				/* decode info as a NSS_SemanticsInformation */
849				PRErrorCode prtn = coder.decodeItem(src->info,
850					kSecAsn1SemanticsInformationTemplate, &srcSI);
851				if(prtn) {
852					clErrorLog("***Error decoding CE_SemanticsInformation\n");
853					CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
854				}
855
856				/* NSS_SemanticsInformation --> CE_SemanticsInformation */
857				dst->semanticsInfo =
858					(CE_SemanticsInformation *)alloc.malloc(sizeof(CE_SemanticsInformation));
859				CE_SemanticsInformation *dstSI = dst->semanticsInfo;
860				memset(dstSI, 0, sizeof(*dstSI));
861				if(srcSI.semanticsIdentifier) {
862					dstSI->semanticsIdentifier = (CSSM_OID *)alloc.malloc(sizeof(CSSM_OID));
863					clAllocCopyData(alloc, *srcSI.semanticsIdentifier, *dstSI->semanticsIdentifier);
864				}
865				if(srcSI.nameRegistrationAuthorities) {
866					dstSI->nameRegistrationAuthorities =
867						(CE_NameRegistrationAuthorities *)alloc.malloc(
868							sizeof(CE_NameRegistrationAuthorities));
869					CL_nssGeneralNamesToCssm(*srcSI.nameRegistrationAuthorities,
870						*dstSI->nameRegistrationAuthorities,
871						coder,
872						alloc);
873				}
874			}
875			else {
876				dst->otherInfo = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA));
877				clAllocCopyData(alloc, src->info, *dst->otherInfo);
878			}
879		}
880	}
881}
882
883void CL_freeQualCertStatements(
884	CE_QC_Statements	&cssmQCs,
885	Allocator			&alloc)
886{
887	uint32 numQCs = cssmQCs.numQCStatements;
888	for(unsigned dex=0; dex<numQCs; dex++) {
889		CE_QC_Statement *dst = &cssmQCs.qcStatements[dex];
890		alloc.free(dst->statementId.Data);
891		if(dst->semanticsInfo) {
892			CE_SemanticsInformation *si = dst->semanticsInfo;
893			if(si->semanticsIdentifier) {
894				alloc.free(si->semanticsIdentifier->Data);
895				alloc.free(si->semanticsIdentifier);
896			}
897			if(si->nameRegistrationAuthorities) {
898				CL_freeCssmGeneralNames(si->nameRegistrationAuthorities, alloc);
899				alloc.free(si->nameRegistrationAuthorities);
900			}
901			alloc.free(si);
902		}
903		if(dst->otherInfo) {
904			alloc.free(dst->otherInfo->Data);
905			alloc.free(dst->otherInfo);
906		}
907	}
908	alloc.free(cssmQCs.qcStatements);
909}
910
911#pragma mark ----- decode/encode CE_DistributionPointName -----
912
913/* This is always a DER-encoded blob at the NSS level */
914void CL_decodeDistributionPointName(
915	const CSSM_DATA				&nssBlob,
916	CE_DistributionPointName	&cssmDpn,
917	SecNssCoder					&coder,
918	Allocator				&alloc)
919{
920	memset(&cssmDpn, 0, sizeof(CE_DistributionPointName));
921	if(nssBlob.Length == 0) {
922		clErrorLog("***CL_decodeDistributionPointName: bad PointName\n");
923		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
924	}
925	unsigned char tag = nssBlob.Data[0] & SEC_ASN1_TAGNUM_MASK;
926	switch(tag) {
927		case NSS_DIST_POINT_FULL_NAME_TAG:
928		{
929			/* decode to temp coder memory */
930			NSS_GeneralNames gnames;
931			gnames.names = NULL;
932			if(coder.decodeItem(nssBlob, kSecAsn1DistPointFullNameTemplate,
933					&gnames)) {
934				clErrorLog("***Error decoding DistPointFullName\n");
935				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
936			}
937
938			cssmDpn.nameType = CE_CDNT_FullName;
939			cssmDpn.dpn.fullName = (CE_GeneralNames *)alloc.malloc(
940				sizeof(CE_GeneralNames));
941
942			/* copy out to caller */
943			CL_nssGeneralNamesToCssm(gnames,
944				*cssmDpn.dpn.fullName, coder, alloc);
945			break;
946		}
947		case NSS_DIST_POINT_RDN_TAG:
948		{
949			/* decode to temp coder memory */
950			NSS_RDN rdn;
951			memset(&rdn, 0, sizeof(rdn));
952			if(coder.decodeItem(nssBlob, kSecAsn1DistPointRDNTemplate,
953					&rdn)) {
954				clErrorLog("***Error decoding DistPointRDN\n");
955				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
956			}
957
958			cssmDpn.nameType = CE_CDNT_NameRelativeToCrlIssuer;
959			cssmDpn.dpn.rdn = (CSSM_X509_RDN_PTR)alloc.malloc(
960				sizeof(CSSM_X509_RDN));
961
962			/* copy out to caller */
963			CL_nssRdnToCssm(rdn, *cssmDpn.dpn.rdn, alloc, coder);
964			break;
965		}
966		default:
967			clErrorLog("***Bad CE_DistributionPointName tag\n");
968			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
969	}
970}
971
972void CL_encodeDistributionPointName(
973	CE_DistributionPointName &cpoint,
974	CSSM_DATA &npoint,
975	SecNssCoder &coder)
976{
977	const SecAsn1Template *templ = NULL;
978	NSS_GeneralNames gnames;
979	NSS_RDN rdn;
980	void *encodeSrc = NULL;
981
982	/*
983	 * Our job is to convert one of two incoming aggregate types
984	 * into NSS format, then encode the result into npoint.
985	 */
986	switch(cpoint.nameType) {
987		case CE_CDNT_FullName:
988			CL_cssmGeneralNamesToNss(*cpoint.dpn.fullName,
989				gnames, coder);
990			encodeSrc = &gnames;
991			templ = kSecAsn1DistPointFullNameTemplate;
992			break;
993
994		case CE_CDNT_NameRelativeToCrlIssuer:
995			CL_cssmRdnToNss(*cpoint.dpn.rdn, rdn, coder);
996			encodeSrc = &rdn;
997			templ = kSecAsn1DistPointRDNTemplate;
998			break;
999		default:
1000			clErrorLog("CL_encodeDistributionPointName: bad nameType\n");
1001			CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
1002	}
1003	if(coder.encodeItem(encodeSrc, templ, npoint)) {
1004		clErrorLog("CL_encodeDistributionPointName: encode error\n");
1005		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
1006	}
1007}
1008
1009
1010#pragma mark --- CE_CRLDistPointsSyntax <--> NSS_CRLDistributionPoints ---
1011
1012void CL_cssmDistPointsToNss(
1013	const CE_CRLDistPointsSyntax 	&cdsaObj,
1014	NSS_CRLDistributionPoints		&nssObj,
1015	SecNssCoder 					&coder)
1016{
1017	memset(&nssObj, 0, sizeof(nssObj));
1018	unsigned numPoints = cdsaObj.numDistPoints;
1019	if(numPoints == 0) {
1020		return;
1021	}
1022	nssObj.distPoints =
1023		(NSS_DistributionPoint **)clNssNullArray(numPoints, coder);
1024	for(unsigned dex=0; dex<numPoints; dex++) {
1025		nssObj.distPoints[dex] = (NSS_DistributionPoint *)
1026			coder.malloc(sizeof(NSS_DistributionPoint));
1027		NSS_DistributionPoint *npoint = nssObj.distPoints[dex];
1028		memset(npoint, 0, sizeof(NSS_DistributionPoint));
1029		CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex];
1030
1031		/* all fields are optional */
1032		if(cpoint->distPointName) {
1033			/* encode and drop into ASN_ANY slot */
1034			npoint->distPointName = (CSSM_DATA *)
1035				coder.malloc(sizeof(CSSM_DATA));
1036			CL_encodeDistributionPointName(*cpoint->distPointName,
1037				*npoint->distPointName, coder);
1038
1039		}
1040
1041		if(cpoint->reasonsPresent) {
1042			/* bit string, presumed max length 8 bits */
1043			coder.allocItem(npoint->reasons, 1);
1044			npoint->reasons.Data[0] = cpoint->reasons;
1045			/* adjust for bit string length */
1046			npoint->reasons.Length = 8;
1047		}
1048
1049		if(cpoint->crlIssuer) {
1050			CL_cssmGeneralNamesToNss(*cpoint->crlIssuer,
1051				npoint->crlIssuer, coder);
1052		}
1053	}
1054}
1055
1056void CL_nssDistPointsToCssm(
1057	const NSS_CRLDistributionPoints	&nssObj,
1058	CE_CRLDistPointsSyntax			&cdsaObj,
1059	SecNssCoder 					&coder,	// for temp decoding
1060	Allocator						&alloc)
1061{
1062	memset(&cdsaObj, 0, sizeof(cdsaObj));
1063	unsigned numPoints = clNssArraySize((const void **)nssObj.distPoints);
1064	if(numPoints == 0) {
1065		return;
1066	}
1067
1068	unsigned len = sizeof(CE_CRLDistributionPoint) * numPoints;
1069	cdsaObj.distPoints = (CE_CRLDistributionPoint *)alloc.malloc(len);
1070	memset(cdsaObj.distPoints, 0, len);
1071	cdsaObj.numDistPoints = numPoints;
1072
1073	for(unsigned dex=0; dex<numPoints; dex++) {
1074		CE_CRLDistributionPoint &cpoint = cdsaObj.distPoints[dex];
1075		NSS_DistributionPoint &npoint = *(nssObj.distPoints[dex]);
1076
1077		/* All three fields are optional */
1078		if(npoint.distPointName != NULL) {
1079			/* Drop in a CE_DistributionPointName */
1080			CE_DistributionPointName *cname =
1081				(CE_DistributionPointName *)alloc.malloc(
1082					sizeof(CE_DistributionPointName));
1083			memset(cname, 0, sizeof(*cname));
1084			cpoint.distPointName = cname;
1085
1086			/*
1087			 * This one is currently still encoded; we have to peek
1088			 * at its tag and decode accordingly.
1089			 */
1090			CL_decodeDistributionPointName(*npoint.distPointName,
1091				*cname, coder, alloc);
1092		}
1093
1094		if(npoint.reasons.Data != NULL) {
1095			/* careful, it's a bit string */
1096			if(npoint.reasons.Length > 8) {
1097				clErrorLog("***CL_nssDistPointsToCssm: Malformed reasons\n");
1098				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
1099			}
1100			cpoint.reasonsPresent = CSSM_TRUE;
1101			if(npoint.reasons.Length != 0) {
1102				cpoint.reasons = npoint.reasons.Data[0];
1103			}
1104		}
1105
1106		if(npoint.crlIssuer.names != NULL) {
1107			/* Cook up a new CE_GeneralNames */
1108			cpoint.crlIssuer =
1109				(CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames));
1110			CL_nssGeneralNamesToCssm(npoint.crlIssuer, *cpoint.crlIssuer,
1111				coder, alloc);
1112		}
1113	}
1114}
1115
1116#pragma mark ----- IssuingDistributionPoint -----
1117
1118void CL_nssIssuingDistPointToCssm(
1119	NSS_IssuingDistributionPoint *nssIdp,
1120	CE_IssuingDistributionPoint	*cssmIdp,
1121	SecNssCoder					&coder,
1122	Allocator					&alloc)
1123{
1124	/* All fields optional */
1125	memset(cssmIdp, 0, sizeof(*cssmIdp));
1126	if(nssIdp->distPointName) {
1127		CE_DistributionPointName *cssmDp = (CE_DistributionPointName *)
1128			alloc.malloc(sizeof(CE_DistributionPointName));
1129
1130		/*
1131		 * This one is currently still encoded; we have to peek
1132		 * at its tag and decode accordingly.
1133		 */
1134		CL_decodeDistributionPointName(*nssIdp->distPointName,
1135			*cssmDp, coder, alloc);
1136		cssmIdp->distPointName = cssmDp;
1137	}
1138	if(nssIdp->onlyUserCerts) {
1139		cssmIdp->onlyUserCertsPresent = CSSM_TRUE;
1140		cssmIdp->onlyUserCerts = clNssBoolToCssm(*nssIdp->onlyUserCerts);
1141	}
1142	if(nssIdp->onlyCACerts) {
1143		cssmIdp->onlyCACertsPresent = CSSM_TRUE;
1144		cssmIdp->onlyCACerts = clNssBoolToCssm(*nssIdp->onlyCACerts);
1145	}
1146	if(nssIdp->onlySomeReasons) {
1147		cssmIdp->onlySomeReasonsPresent = CSSM_TRUE;
1148		if(nssIdp->onlySomeReasons->Length > 0) {
1149			cssmIdp->onlySomeReasons = *nssIdp->onlySomeReasons->Data;
1150		}
1151		else {
1152			cssmIdp->onlySomeReasons = 0;
1153		}
1154	}
1155	if(nssIdp->indirectCRL) {
1156		cssmIdp->indirectCrlPresent = CSSM_TRUE;
1157		cssmIdp->indirectCrl = clNssBoolToCssm(*nssIdp->indirectCRL);
1158	}
1159}
1160
1161#pragma mark --- CE_NameConstraints <--> NSS_NameConstraints ---
1162
1163void CL_cssmNameConstraintsToNss(
1164	const CE_NameConstraints		&cdsaObj,
1165	NSS_NameConstraints				&nssObj,
1166	SecNssCoder						&coder)
1167{
1168	//%%%FIXME tba
1169}
1170
1171void CL_nssNameConstraintsToCssm(
1172	const NSS_NameConstraints		&nssObj,
1173	CE_NameConstraints				&cdsaObj,
1174	SecNssCoder 					&coder,	// for temp decoding
1175	Allocator						&alloc)
1176{
1177	//%%%FIXME tba
1178}
1179
1180void CL_freeCssmNameConstraints(
1181	CE_NameConstraints				*cssmNcs,
1182	Allocator						&alloc)
1183{
1184	if(cssmNcs == NULL) {
1185		return;
1186	}
1187//%%%FIXME need to add a CL_freeCssmGeneralSubtrees function to clNameUtils{.h,.cpp}
1188#if 0
1189	switch(cssmDpn->nameType) {
1190		case CE_CDNT_FullName:
1191			CL_freeCssmGeneralNames(cssmDpn->dpn.fullName, alloc);
1192			alloc.free(cssmDpn->dpn.fullName);
1193			break;
1194		case CE_CDNT_NameRelativeToCrlIssuer:
1195			CL_freeX509Rdn(cssmDpn->dpn.rdn, alloc);
1196			alloc.free(cssmDpn->dpn.rdn);
1197			break;
1198	}
1199#endif
1200	memset(cssmNcs, 0, sizeof(*cssmNcs));
1201}
1202
1203#pragma mark --- CE_PolicyMappings <--> NSS_PolicyMappings ---
1204
1205void CL_cssmPolicyMappingsToNss(
1206	const CE_PolicyMappings			&cdsaObj,
1207	NSS_PolicyMappings				&nssObj,
1208	SecNssCoder						&coder)
1209{
1210	//%%%FIXME tba
1211}
1212
1213void CL_nssPolicyMappingsToCssm(
1214	const NSS_PolicyMappings		&nssObj,
1215	CE_PolicyMappings				&cdsaObj,
1216	SecNssCoder 					&coder,	// for temp decoding
1217	Allocator						&alloc)
1218{
1219	//%%%FIXME tba
1220}
1221
1222void CL_freeCssmPolicyMappings(
1223	CE_PolicyMappings				*cssmPms,
1224	Allocator						&alloc)
1225{
1226	if(cssmPms == NULL) {
1227		return;
1228	}
1229	//%%%FIXME tba
1230
1231	memset(cssmPms, 0, sizeof(*cssmPms));
1232}
1233
1234#pragma mark --- CE_PolicyConstraints <--> NSS_PolicyConstraints ---
1235
1236void CL_cssmPolicyConstraintsToNss(
1237	const CE_PolicyConstraints		*cdsaObj,
1238	NSS_PolicyConstraints			*nssObj,
1239	SecNssCoder						&coder)
1240{
1241	//%%%FIXME tba
1242}
1243
1244void CL_nssPolicyConstraintsToCssm(
1245	const NSS_PolicyConstraints		*nssObj,
1246	CE_PolicyConstraints			*cdsaObj,
1247	SecNssCoder 					&coder,	// for temp decoding
1248	Allocator						&alloc)
1249{
1250	memset(cdsaObj, 0, sizeof(*cdsaObj));
1251	if(nssObj->requireExplicitPolicy.Data) {
1252		cdsaObj->requireExplicitPolicyPresent = CSSM_TRUE;
1253		cdsaObj->inhibitPolicyMapping = clDataToInt(
1254			nssObj->requireExplicitPolicy, 0);
1255	}
1256	if(nssObj->inhibitPolicyMapping.Data) {
1257		cdsaObj->inhibitPolicyMappingPresent = CSSM_TRUE;
1258		cdsaObj->inhibitPolicyMapping = clDataToInt(
1259			nssObj->inhibitPolicyMapping, 0);
1260	}
1261}
1262
1263void CL_freeCssmPolicyConstraints(
1264	CE_PolicyConstraints			*cssmPcs,
1265	Allocator						&alloc)
1266{
1267	if(cssmPcs == NULL) {
1268		return;
1269	}
1270
1271	memset(cssmPcs, 0, sizeof(*cssmPcs));
1272}
1273
1274
1275#pragma mark ----- ECDSA_SigAlgParams support -----
1276
1277/*
1278 * Some implementations use a two-OID mechanism to specify ECDSA signature
1279 * algorithm with a digest of other than SHA1. This is really not necessary;
1280 * we use the single-OID method (e.g. CSSMOID_ECDSA_WithSHA512) when
1281 * encoding, but we have to accomodate externally generated items with
1282 * the two-OID method. This routine decodes the digest OID and infers a
1283 * CSSM_ALGORITHMS from it.
1284 * Throws CSSMERR_CL_UNKNOWN_FORMAT on any error.
1285 */
1286CSSM_ALGORITHMS CL_nssDecodeECDSASigAlgParams(
1287	const CSSM_DATA &encParams,
1288	SecNssCoder &coder)
1289{
1290	CSSM_X509_ALGORITHM_IDENTIFIER algParams;
1291	memset(&algParams, 0, sizeof(algParams));
1292	PRErrorCode prtn = coder.decodeItem(encParams, kSecAsn1AlgorithmIDTemplate, &algParams);
1293	if(prtn) {
1294		clErrorLog("CL_nssDecodeECDSASigAlgParams: error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n");
1295		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
1296	}
1297
1298	/* get the digest algorithm, convert to ECDSA w/digest OID */
1299	CSSM_ALGORITHMS digestAlg = CL_oidToAlg(algParams.algorithm);
1300	switch(digestAlg) {
1301		case CSSM_ALGID_SHA1:
1302			return CSSM_ALGID_SHA1WithECDSA;
1303		case CSSM_ALGID_SHA224:
1304			return CSSM_ALGID_SHA224WithECDSA;
1305		case CSSM_ALGID_SHA256:
1306			return CSSM_ALGID_SHA256WithECDSA;
1307		case CSSM_ALGID_SHA384:
1308			return CSSM_ALGID_SHA384WithECDSA;
1309		case CSSM_ALGID_SHA512:
1310			return CSSM_ALGID_SHA512WithECDSA;
1311		default:
1312			clErrorLog("CL_nssDecodeECDSASigAlgParams: unknown digest algorithm\n");
1313			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
1314	}
1315}
1316
1317#pragma mark ----- Top-level Cert/CRL encode and decode -----
1318
1319/*
1320 * To ensure a secure means of signing and verifying TBSCert blobs, we
1321 * provide these functions to encode and decode just the top-level
1322 * elements of a certificate. Unfortunately there is no guarantee
1323 * that when you decode and re-encode a TBSCert blob, you get the
1324 * same thing you started with (although with DER rules, as opposed
1325 * to BER rules, you should). Thus when signing, we sign the TBSCert
1326 * and encode the signed cert here without ever decoding the TBSCert (or,
1327 * at least, without using the decoded version to get the encoded TBS blob).
1328 */
1329
1330void CL_certCrlDecodeComponents(
1331	const CssmData 	&signedItem,		// DER-encoded cert or CRL
1332	CssmOwnedData	&tbsBlob,			// still DER-encoded
1333	CssmOwnedData	&algId,				// ditto
1334	CssmOwnedData	&rawSig)			// raw bits (not an encoded AsnBits)
1335{
1336	/* BER-decode into temp memory */
1337	NSS_SignedCertOrCRL nssObj;
1338	SecNssCoder coder;
1339	PRErrorCode prtn;
1340
1341	memset(&nssObj, 0, sizeof(nssObj));
1342	prtn = coder.decode(signedItem.data(), signedItem.length(),
1343		kSecAsn1SignedCertOrCRLTemplate, &nssObj);
1344	if(prtn) {
1345		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
1346	}
1347
1348	/* tbsBlob and algId are raw ASN_ANY including tags, which we pass
1349	 * back to caller intact */
1350	tbsBlob.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length);
1351	algId.copy(nssObj.signatureAlgorithm.Data,
1352		nssObj.signatureAlgorithm.Length);
1353
1354	/* signature is a bit string which we do in fact decode */
1355	rawSig.copy(nssObj.signature.Data,
1356		(nssObj.signature.Length + 7) / 8);
1357}
1358
1359
1360/*
1361 * Given pre-DER-encoded blobs, do the final encode step for a signed cert.
1362 */
1363void
1364CL_certEncodeComponents(
1365	const CssmData		&TBSCert,		// DER-encoded
1366	const CssmData		&algId,			// ditto
1367	const CssmData		&rawSig,		// raw bits, not encoded
1368	CssmOwnedData 		&signedCert)	// DER-encoded
1369{
1370	NSS_SignedCertOrCRL nssObj;
1371	nssObj.tbsBlob.Data = TBSCert.Data;
1372	nssObj.tbsBlob.Length = TBSCert.Length;
1373	nssObj.signatureAlgorithm.Data = algId.Data;
1374	nssObj.signatureAlgorithm.Length = algId.Length;
1375	nssObj.signature.Data = rawSig.Data;
1376	nssObj.signature.Length = rawSig.Length * 8;	// BIT STRING
1377
1378	PRErrorCode prtn;
1379
1380	prtn = SecNssEncodeItemOdata(&nssObj,
1381		kSecAsn1SignedCertOrCRLTemplate,signedCert);
1382	if(prtn) {
1383		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
1384	}
1385
1386}
1387