/* This is always a DER-encoded blob at the NSS level */
void CL_decodeDistributionPointName(
	const CSSM_DATA				&nssBlob,
	CE_DistributionPointName	&cssmDpn,
	SecNssCoder					&coder,
	Allocator				&alloc)
{
	memset(&cssmDpn, 0, sizeof(CE_DistributionPointName));
	if(nssBlob.Length == 0) {
		clErrorLog("***CL_decodeDistributionPointName: bad PointName\n");
		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
	unsigned char tag = nssBlob.Data[0] & SEC_ASN1_TAGNUM_MASK;
	switch(tag) {
		case NSS_DIST_POINT_FULL_NAME_TAG:
		{
			/* decode to temp coder memory */
			NSS_GeneralNames gnames;
			gnames.names = NULL;
			if(coder.decodeItem(nssBlob, kSecAsn1DistPointFullNameTemplate,
					&gnames)) {
				clErrorLog("***Error decoding DistPointFullName\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			
			cssmDpn.nameType = CE_CDNT_FullName;
			cssmDpn.dpn.fullName = (CE_GeneralNames *)alloc.malloc(
				sizeof(CE_GeneralNames));
				
			/* copy out to caller */
			CL_nssGeneralNamesToCssm(gnames, 
				*cssmDpn.dpn.fullName, coder, alloc);
			break;
		}
		case NSS_DIST_POINT_RDN_TAG:
		{
			/* decode to temp coder memory */
			NSS_RDN rdn;
			memset(&rdn, 0, sizeof(rdn));
			if(coder.decodeItem(nssBlob, kSecAsn1DistPointRDNTemplate,
					&rdn)) {
				clErrorLog("***Error decoding DistPointRDN\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			
			cssmDpn.nameType = CE_CDNT_NameRelativeToCrlIssuer;
			cssmDpn.dpn.rdn = (CSSM_X509_RDN_PTR)alloc.malloc(
				sizeof(CSSM_X509_RDN));
			
			/* copy out to caller */
			CL_nssRdnToCssm(rdn, *cssmDpn.dpn.rdn, alloc, coder);
			break;
		}
		default:
			clErrorLog("***Bad CE_DistributionPointName tag\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
}
static int writeAuthSafeContent(
	const CSSM_DATA &rawBlob, 
	const char *outFile,
	SecNssCoder &coder,
	OidParser &parser)
{
	NSS_P12_RawPFX pfx;
	memset(&pfx, 0, sizeof(pfx));
	if(coder.decodeItem(rawBlob, NSS_P12_RawPFXTemplate, &pfx)) {
		printf("***Error on top-level decode of NSS_P12_RawPFX\n");
		return 1;
	}
	printf("...version = %u\n", (unsigned)dataToInt(pfx.version));
	NSS_P7_RawContentInfo &rci = pfx.authSafe;
	printf("...contentType = %s\n", oidStr(rci.contentType, parser));
	
	/* parse content per OID the only special case is PKCS7_Data,
	 * which we unwrap from an octet string before writing it */
	CSSM_DATA toWrite;
	if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_Data)) {
		if(coder.decodeItem(rci.content, SEC_OctetStringTemplate,
				&toWrite)) {
			printf("***Error decoding PKCS7_Data Octet string; writing"
				" raw contents\n");
			toWrite = rci.content;
		}
	}
	else if(nssCompareCssmData(&rci.contentType, 
			&CSSMOID_PKCS7_SignedData)) {
		/* the only other legal content type here */
		/* This is encoded SignedData which I am not even close
		 * to worrying about - Panther p12 won't do this */
		toWrite = rci.content;
	}
	else {
		printf("***writeAuthSafeContent: bad contentType\n");
		return 1;
	}
	if(writeFile(outFile, toWrite.Data, toWrite.Length)) {
		printf("***Error writing to %s\n", outFile);
		return 1;
	}
	else {
		printf("...%u bytes written to %s\n", 
			(unsigned)toWrite.Length, outFile);
		return 0;
	}
}
/*
 * Parse an CSSM_X509_ALGORITHM_IDENTIFIER specific to P12.
 * Decode the alg params as a NSS_P12_PBE_Params and parse and 
 * return the result if the pbeParams is non-NULL.
 */
void P12Coder::algIdParse(
	const CSSM_X509_ALGORITHM_IDENTIFIER &algId,
	NSS_P12_PBE_Params *pbeParams,		// optional
	SecNssCoder &localCdr)
{
	p12DecodeLog("algIdParse");

	const CSSM_DATA &param = algId.parameters;
	if(pbeParams == NULL) {
		/* alg params are uninterpreted */
		return;
	}
	
	if(param.Length == 0) {
		p12ErrorLog("algIdParse: no alg parameters\n");
		P12_THROW_DECODE;
	}
	
	memset(pbeParams, 0, sizeof(*pbeParams));
	if(localCdr.decodeItem(param, 
			NSS_P12_PBE_ParamsTemplate, pbeParams)) {
		p12ErrorLog("Error decoding NSS_P12_PBE_Params\n");
		P12_THROW_DECODE;
	}
}
void CL_infoAccessToCssm(
	const NSS_AuthorityInfoAccess 	&nssObj,
	CE_AuthorityInfoAccess			&cdsaObj,
	SecNssCoder						&coder,	// for temp decoding
	Allocator						&alloc)
{
	memset(&cdsaObj, 0, sizeof(cdsaObj));
	unsigned numDescs = clNssArraySize((const void **)nssObj.accessDescriptions);
	if(numDescs == 0) {
		return;
	}
	cdsaObj.accessDescriptions = (CE_AccessDescription *)alloc.malloc(
		numDescs * sizeof(CE_AccessDescription));
	cdsaObj.numAccessDescriptions = numDescs;
	for(unsigned dex=0; dex<numDescs; dex++) {
		CE_AccessDescription *dst = &cdsaObj.accessDescriptions[dex];
		NSS_AccessDescription *src = nssObj.accessDescriptions[dex];
		clAllocCopyData(alloc, src->accessMethod, dst->accessMethod);
		
		/* decode the general name */
		NSS_GeneralName nssGenName;
		memset(&nssGenName, 0, sizeof(nssGenName));
		PRErrorCode prtn = coder.decodeItem(src->encodedAccessLocation,
			kSecAsn1GeneralNameTemplate, &nssGenName);
		if(prtn) {
			clErrorLog("***Error decoding NSS_AuthorityInfoAccess.accessLocation\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
		}
		
		/* then convert the result to CSSM */
		CL_nssGeneralNameToCssm(nssGenName, dst->accessLocation, coder, alloc);
	}
}
/* 
 * Some implementations use a two-OID mechanism to specify ECDSA signature
 * algorithm with a digest of other than SHA1. This is really not necessary;
 * we use the single-OID method (e.g. CSSMOID_ECDSA_WithSHA512) when 
 * encoding, but we have to accomodate externally generated items with 
 * the two-OID method. This routine decodes the digest OID and infers a 
 * CSSM_ALGORITHMS from it.
 * Throws CSSMERR_CL_UNKNOWN_FORMAT on any error.
 */
CSSM_ALGORITHMS CL_nssDecodeECDSASigAlgParams(
	const CSSM_DATA &encParams,
	SecNssCoder &coder)
{
	CSSM_X509_ALGORITHM_IDENTIFIER algParams;
	memset(&algParams, 0, sizeof(algParams));
	PRErrorCode prtn = coder.decodeItem(encParams, kSecAsn1AlgorithmIDTemplate, &algParams);
	if(prtn) {
		clErrorLog("CL_nssDecodeECDSASigAlgParams: error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n");
		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
	
	/* get the digest algorithm, convert to ECDSA w/digest OID */
	CSSM_ALGORITHMS digestAlg = CL_oidToAlg(algParams.algorithm);
	switch(digestAlg) {
		case CSSM_ALGID_SHA1:
			return CSSM_ALGID_SHA1WithECDSA;
		case CSSM_ALGID_SHA224:
			return CSSM_ALGID_SHA224WithECDSA;
		case CSSM_ALGID_SHA256:
			return CSSM_ALGID_SHA256WithECDSA;
		case CSSM_ALGID_SHA384:
			return CSSM_ALGID_SHA384WithECDSA;
		case CSSM_ALGID_SHA512:
			return CSSM_ALGID_SHA512WithECDSA;
		default:
			clErrorLog("CL_nssDecodeECDSASigAlgParams: unknown digest algorithm\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
}
/* 
 * Convert a CSSM_KEY to a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. The
 * CSSM key must be in raw format and with a specific blob format.
 *  	-- RSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_PKCS1
 * 		-- DSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
 * 		-- ECDSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509
 */
void CL_CSSMKeyToSubjPubKeyInfoNSS(
	const CSSM_KEY 						&cssmKey,
	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO	&nssKeyInfo,
	SecNssCoder							&coder)
{
	const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
	if(hdr.BlobType != CSSM_KEYBLOB_RAW) {
		clErrorLog("CL SetField: must specify RAW key blob\n");
		CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
	}
	memset(&nssKeyInfo, 0, sizeof(nssKeyInfo));
	
	/* algorithm and format dependent from here... */
	switch(hdr.AlgorithmId) {
		case CSSM_ALGID_RSA:
			if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
				clErrorLog("CL SetField: RSA key must be in PKCS1 format\n");
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
			}
			/* and fall thru */
		default:
		{
			/* Key header's algorithm --> OID */
			const CSSM_OID *oid = cssmAlgToOid(hdr.AlgorithmId);
			if(oid == NULL) {
				clErrorLog("CL SetField: Unknown key algorithm\n");
				CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
			}
			CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssKeyInfo.algorithm;
			coder.allocCopyItem(*oid, algId.algorithm);

			/* NULL algorithm parameters, always in this case */
			CL_nullAlgParams(algId);
			
			/* Copy key bits, destination is a BIT STRING */
			coder.allocCopyItem(cssmKey.KeyData, nssKeyInfo.subjectPublicKey);
			nssKeyInfo.subjectPublicKey.Length *= 8;
			break;
		}	
		case CSSM_ALGID_DSA:
		case CSSM_ALGID_ECDSA:
			if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_X509) {
				clErrorLog("CL SetField: DSA/ECDSA key must be in X509 format\n");
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
			}
			
			/* 
			 * All we do is decode the whole key blob into the 
			 * SubjectPublicKeyInfo.
			 */
			if(coder.decodeItem(cssmKey.KeyData, 
					kSecAsn1SubjectPublicKeyInfoTemplate, 
					&nssKeyInfo)) {
				clErrorLog("CL SetField: Error decoding DSA public key\n");
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
			}
			break;
	}
}
/*
 * Parse an encoded NSS_P12_SafeContents. This could be either 
 * present as plaintext in an AuthSafe or decrypted. 
 */
void P12Coder::safeContentsParse(
	const CSSM_DATA &contentsBlob,
	SecNssCoder &localCdr)
{
	p12DecodeLog("safeContentsParse");

	NSS_P12_SafeContents sc;
	memset(&sc, 0, sizeof(sc));
	if(localCdr.decodeItem(contentsBlob, NSS_P12_SafeContentsTemplate,
			&sc)) {
		p12ErrorLog("Error decoding SafeContents\n");
		P12_THROW_DECODE;
	}
	unsigned numBags = nssArraySize((const void **)sc.bags);
	for(unsigned dex=0; dex<numBags; dex++) {
		NSS_P12_SafeBag *bag = sc.bags[dex];
		assert(bag != NULL);
		
		/* ensure that *something* is there */
		if(bag->bagValue.keyBag == NULL) {
			p12ErrorLog("safeContentsParse: Empty SafeBag\n");
			P12_THROW_DECODE;
		}
		
		/*
		 * Break out to individual bag type
		 */
		switch(bag->type) {
			case BT_KeyBag:
				keyBagParse(*bag, localCdr);
				break;
			case BT_ShroudedKeyBag:
				shroudedKeyBagParse(*bag, localCdr);
				break;
			case BT_CertBag:
				certBagParse(*bag, localCdr);
				break;
			case BT_CrlBag:
				crlBagParse(*bag, localCdr);
				break;
			case BT_SecretBag:
				secretBagParse(*bag ,localCdr);
				break;
			case BT_SafeContentsBag:
				safeContentsBagParse(*bag, localCdr);
				break;
			default:
				p12ErrorLog("unknown  p12 BagType (%u)\n",
					(unsigned)bag->type);
				P12_THROW_DECODE;
		}
	}
}
/* top-level PKCS12 PFX decoder */
void P12Coder::decode(
	CFDataRef				cdpfx)
{
	SecNssCoder localCdr;
	NSS_P12_DecodedPFX pfx;

	p12DecodeLog("decode");
	memset(&pfx, 0, sizeof(pfx));
	const CSSM_DATA rawBlob = {int_cast<CFIndex, CSSM_SIZE>(CFDataGetLength(cdpfx)),
		(uint8 *)CFDataGetBytePtr(cdpfx)};
		
	if(localCdr.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) {
		p12ErrorLog("Error on top-level decode of NSS_P12_DecodedPFX\n");
		P12_THROW_DECODE;
	}
	NSS_P7_DecodedContentInfo &dci = pfx.authSafe;
	if(dci.type != CT_Data) {
		/* no other types supported yet */
		p12ErrorLog("bad top-level contentType\n");
		P12_THROW_DECODE;
	}
	mIntegrityMode = kSecPkcs12ModePassword;

	if(pfx.macData == NULL) {
		/* not present is an error in kSecPkcs12ModePassword */
		p12ErrorLog("no MAC in PFX\n");
		P12_THROW_DECODE;
	}
	macParse(*pfx.macData, localCdr);

	const CSSM_DATA *macPhrase = getMacPassPhrase();
	const CSSM_KEY *macPassKey = getMacPassKey();
	if((macPhrase == NULL) && (macPassKey == NULL)) {
		p12ErrorLog("no passphrase set\n");
		CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE);
	}
	CSSM_RETURN crtn = p12VerifyMac(pfx, mCspHand, macPhrase, 
		macPassKey, localCdr);
	if(crtn) {
		p12LogCssmError("p12VerifyMac", crtn);
		CssmError::throwMe(errSecPkcs12VerifyFailure);
	}
	
	authSafeParse(*dci.content.data, localCdr);

	/*
	 * On success, if we have a keychain, store certs and CRLs there
	 */
	if(mKeychain != NULL) {
		storeDecodeResults();
	}
}
/*
 * Parse an encoded NSS_P12_AuthenticatedSafe
 */
void P12Coder::authSafeParse(
	const CSSM_DATA &authSafeBlob,
	SecNssCoder &localCdr)
{
	p12DecodeLog("authSafeParse");

	NSS_P12_AuthenticatedSafe authSafe;
	
	memset(&authSafe, 0, sizeof(authSafe));
	if(localCdr.decodeItem(authSafeBlob,
			NSS_P12_AuthenticatedSafeTemplate,
			&authSafe)) {
		p12ErrorLog("Error decoding authSafe\n");
		P12_THROW_DECODE;
	}
	unsigned numInfos = nssArraySize((const void **)authSafe.info);
	for(unsigned dex=0; dex<numInfos; dex++) {
		NSS_P7_DecodedContentInfo *info = authSafe.info[dex];
		authSafeElementParse(info, localCdr);
	}
}
void CL_nssGeneralNamesToCssm(
	const NSS_GeneralNames &nssObj,
	CE_GeneralNames &cdsaObj,
	SecNssCoder &coder,				// for temp decoding
	Allocator &alloc)			// destination 
{
	memset(&cdsaObj, 0, sizeof(cdsaObj));
	unsigned numNames = clNssArraySize((const void **)nssObj.names);
	if(numNames == 0) {
		return;
	}
	
	/*
	 * Decode each name element, currently a raw ASN_ANY blob.
	 * Then convert each result into CDSA form.
	 * This array of (NSS_GeneralName)s is temporary, it doesn't
	 * persist outside of this routine other than the fact that it's
	 * mallocd by the coder arena pool. 
	 */
	NSS_GeneralName *names = 
		(NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames);
	memset(names, 0, sizeof(NSS_GeneralName) * numNames);
	cdsaObj.generalName = (CE_GeneralName *)alloc.malloc(
		sizeof(CE_GeneralName) * numNames);
	cdsaObj.numNames = numNames;
	
	for(unsigned dex=0; dex<numNames; dex++) {
		if(coder.decodeItem(*nssObj.names[dex], kSecAsn1GeneralNameTemplate,
				&names[dex])) {
			clErrorLog("***CL_nssGeneralNamesToCssm: Error decoding "
				"General.name\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
		}
		
		CL_nssGeneralNameToCssm(names[dex],
			cdsaObj.generalName[dex],
			coder, alloc);
	}
}
void CL_nssGeneralNameToCssm(
	NSS_GeneralName &nssObj,
	CE_GeneralName &cdsaObj,
	SecNssCoder &coder,				// for temp decoding
	Allocator &alloc)			// destination 
{
	memset(&cdsaObj, 0, sizeof(cdsaObj));
	PRErrorCode prtn;

	/* for caller's CE_GeneralName */
	CSSM_BOOL berEncoded = CSSM_FALSE;
	CE_GeneralNameType cdsaTag;
	
	/*
	 * At this point, depending on the decoded object's tag, we either
	 * have the final bytes to copy out, or we need to decode further.
	 * After this switch, if doCopy is true, give the caller a copy
	 * of nssObj.item.
	 */
	bool doCopy = true;
	switch(nssObj.tag) {
		case NGT_OtherName:		// ASN_ANY -> CE_OtherName
		{
			cdsaTag = GNT_OtherName;
			
			/* decode to coder memory */
			CE_OtherName *nssOther = 
				(CE_OtherName *)coder.malloc(sizeof(CE_OtherName));
			memset(nssOther, 0, sizeof(CE_OtherName));
			prtn = coder.decodeItem(nssObj.item, 
				kSecAsn1GenNameOtherNameTemplate, 
				nssOther);
			if(prtn) {
				clErrorLog("CL_nssGeneralNameToCssm: error decoding "
						"OtherName\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			
			/* copy out to caller */
			clAllocData(alloc, cdsaObj.name, sizeof(CE_OtherName));
			clCopyOtherName(*nssOther, *((CE_OtherName *)cdsaObj.name.Data), 
				alloc);
			doCopy = false;
			break;
		}
		case NGT_RFC822Name:	// IA5String, done
			cdsaTag = GNT_RFC822Name;
			break;
		case NGT_DNSName:		// IA5String
			cdsaTag = GNT_DNSName;
			break;
		case NGT_X400Address:	// ASY_ANY, leave alone
			cdsaTag = GNT_X400Address;
			berEncoded = CSSM_TRUE;
			break;
		case NGT_DirectoryName:	// ASN_ANY --> NSS_Name
		{
			cdsaTag = GNT_DirectoryName;
			
			/* Decode to coder memory */
			NSS_Name *nssName = (NSS_Name *)coder.malloc(sizeof(NSS_Name));
			memset(nssName, 0, sizeof(NSS_Name));
			prtn = coder.decodeItem(nssObj.item, kSecAsn1NameTemplate, nssName);
			if(prtn) {
				clErrorLog("CL_nssGeneralNameToCssm: error decoding "
						"NSS_Name\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			
			/* convert & copy out to caller */
			clAllocData(alloc, cdsaObj.name, sizeof(CSSM_X509_NAME));
			CL_nssNameToCssm(*nssName, 
				*((CSSM_X509_NAME *)cdsaObj.name.Data), alloc);
			doCopy = false;
			break;
		}
		case NGT_EdiPartyName:	// ASN_ANY, leave alone
			cdsaTag = GNT_EdiPartyName;
			berEncoded = CSSM_TRUE;
			break;
		case NGT_URI:			// IA5String
			cdsaTag = GNT_URI;
			break;
		case NGT_IPAddress:		// OCTET_STRING
			cdsaTag = GNT_IPAddress;
			break;
		case NGT_RegisteredID:	// OID
			cdsaTag = GNT_RegisteredID;
			break;
		default:
			clErrorLog("CL_nssGeneralNameToCssm: bad name tag\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}	
	
	cdsaObj.nameType = cdsaTag;
	cdsaObj.berEncoded = berEncoded;
	if(doCopy) {
		clAllocCopyData(alloc, nssObj.item, cdsaObj.name);
	}
}
Example #12
0
void CL_qualCertStatementsToCssm(
	const NSS_QC_Statements 		&nssObj,
	CE_QC_Statements 				&cdsaObj,
	SecNssCoder 					&coder,	// for temp decoding
	Allocator						&alloc)
{
	memset(&cdsaObj, 0, sizeof(cdsaObj));
	unsigned numQcs = clNssArraySize((const void **)nssObj.qcStatements);
	if(numQcs == 0) {
		return;
	}
	cdsaObj.qcStatements = (CE_QC_Statement *)alloc.malloc(
		numQcs * sizeof(CE_AccessDescription));
	cdsaObj.numQCStatements = numQcs;
	for(unsigned dex=0; dex<numQcs; dex++) {
		CE_QC_Statement *dst = &cdsaObj.qcStatements[dex];
		NSS_QC_Statement *src = nssObj.qcStatements[dex];

		memset(dst, 0, sizeof(*dst));
		clAllocCopyData(alloc, src->statementId, dst->statementId);

		/* 
		 * Whether the optional info is a SemanticsInformation or is uninterpreted
 		 * DER data depends on statementId.
		 */
		if(src->info.Data) {
			if(clCompareCssmData(&src->statementId, &CSSMOID_OID_QCS_SYNTAX_V2)) {
				NSS_SemanticsInformation srcSI;
				memset(&srcSI, 0, sizeof(srcSI));

				/* decode info as a NSS_SemanticsInformation */
				PRErrorCode prtn = coder.decodeItem(src->info,
					kSecAsn1SemanticsInformationTemplate, &srcSI);
				if(prtn) {
					clErrorLog("***Error decoding CE_SemanticsInformation\n");
					CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
				}

				/* NSS_SemanticsInformation --> CE_SemanticsInformation */
				dst->semanticsInfo = 
					(CE_SemanticsInformation *)alloc.malloc(sizeof(CE_SemanticsInformation));
				CE_SemanticsInformation *dstSI = dst->semanticsInfo;
				memset(dstSI, 0, sizeof(*dstSI));
				if(srcSI.semanticsIdentifier) {
					dstSI->semanticsIdentifier = (CSSM_OID *)alloc.malloc(sizeof(CSSM_OID));
					clAllocCopyData(alloc, *srcSI.semanticsIdentifier, *dstSI->semanticsIdentifier);
				}
				if(srcSI.nameRegistrationAuthorities) {
					dstSI->nameRegistrationAuthorities = 
						(CE_NameRegistrationAuthorities *)alloc.malloc(
							sizeof(CE_NameRegistrationAuthorities));
					CL_nssGeneralNamesToCssm(*srcSI.nameRegistrationAuthorities, 
						*dstSI->nameRegistrationAuthorities,
						coder,
						alloc);
				}
			}
			else {
				dst->otherInfo = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA));
				clAllocCopyData(alloc, src->info, *dst->otherInfo);
			}
		}
	}
}