Exemplo n.º 1
0
void CL_nssDistPointsToCssm(
	const NSS_CRLDistributionPoints	&nssObj,
	CE_CRLDistPointsSyntax			&cdsaObj,
	SecNssCoder 					&coder,	// for temp decoding
	Allocator						&alloc)
{
	memset(&cdsaObj, 0, sizeof(cdsaObj));
	unsigned numPoints = clNssArraySize((const void **)nssObj.distPoints);
	if(numPoints == 0) {
		return;
	}
	
	unsigned len = sizeof(CE_CRLDistributionPoint) * numPoints;
	cdsaObj.distPoints = (CE_CRLDistributionPoint *)alloc.malloc(len);
	memset(cdsaObj.distPoints, 0, len);
	cdsaObj.numDistPoints = numPoints;

	for(unsigned dex=0; dex<numPoints; dex++) {
		CE_CRLDistributionPoint &cpoint = cdsaObj.distPoints[dex];
		NSS_DistributionPoint &npoint = *(nssObj.distPoints[dex]);
	
		/* All three fields are optional */
		if(npoint.distPointName != NULL) {
			/* Drop in a CE_DistributionPointName */
			CE_DistributionPointName *cname = 
				(CE_DistributionPointName *)alloc.malloc(
					sizeof(CE_DistributionPointName));
			memset(cname, 0, sizeof(*cname));
			cpoint.distPointName = cname;
			
			/*
			 * This one is currently still encoded; we have to peek
			 * at its tag and decode accordingly.
			 */
			CL_decodeDistributionPointName(*npoint.distPointName,
				*cname, coder, alloc);
		}

		if(npoint.reasons.Data != NULL) {
			/* careful, it's a bit string */
			if(npoint.reasons.Length > 8) {
				clErrorLog("***CL_nssDistPointsToCssm: Malformed reasons\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			cpoint.reasonsPresent = CSSM_TRUE;
			if(npoint.reasons.Length != 0) {
				cpoint.reasons = npoint.reasons.Data[0];
			}
		}
		
		if(npoint.crlIssuer.names != NULL) {
			/* Cook up a new CE_GeneralNames */
			cpoint.crlIssuer = 
				(CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames));
			CL_nssGeneralNamesToCssm(npoint.crlIssuer, *cpoint.crlIssuer,
				coder, alloc);
		}
	}
}
Exemplo n.º 2
0
/*
 * Given a fully encoded BER object, create a CSSM_X509EXT_TAGandVALUE
 * representing it. We malloc the CSSM_X509EXT_TAGandVALUE itself using
 * specified allocator, but the referent (in CSSM_X509EXT_TAGandVALUE.value)
 * merely points to data inside the berValue.
 */
CSSM_X509EXT_TAGandVALUE *DecodedExten::createTagAndValue(
    const CSSM_DATA &berValue,
    Allocator &alloc) const
{
    if((berValue.Data == NULL) || (berValue.Length == 0)) {
        return NULL;
    }
    CSSM_X509EXT_TAGandVALUE *tv = (CSSM_X509EXT_TAGandVALUE *)
                                   alloc.malloc(sizeof(CSSM_X509EXT_TAGandVALUE));

    // Important: by the time we get called, the extension data
    // has already been deconstructed, and the raw value we are
    // handed in berValue does not include ASN.1 type or length.
    // Since createTagAndValue is only called in the case where
    // the contents are unknown (and thus opaque), always treat
    // as an octet string.

    tv->type = SEC_ASN1_OCTET_STRING;
    tv->value.Length = berValue.Length;
    tv->value.Data = berValue.Data;
    return tv;

#if 0
    tv->type = berValue.Data[0];

    /*
     * length of length is variable; ASN spec says it can actually be up to
     * 127 bytes, but we only have room for 32 bits!
     */
    const uint8 *lp = berValue.Data + 1;
    uint8 len1 = *lp;
    if((len1 & 0x80) == 0) {
        /* short form */
        tv->value.Length = len1;
        tv->value.Data = const_cast<uint8 *>(lp + 1);
        return tv;
    }

    unsigned numLenBytes = len1 & 0x7f;
    if(numLenBytes > 4) {
        clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes);
        alloc.free(tv);
        CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
    }

    uint32 len = 0;
    lp++;			// points to first length byte
    for(uint32 dex=0; dex<numLenBytes; dex++) {
        len <<= 8;
        len += *lp;
        lp++;
    }
    tv->value.Length = len;
    tv->value.Data = const_cast<uint8 *>(lp);
    return tv;
#endif
}
Exemplo n.º 3
0
CSSM_ALGORITHMS CL_oidToAlg(
	const CSSM_OID &oid)
{
	CSSM_ALGORITHMS alg;
	bool found = cssmOidToAlg(&oid, &alg);
	if(!found) {
		clErrorLog("CL_oidToAlg: unknown alg\n");
		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
	return alg;
}
Exemplo n.º 4
0
void CL_cssmQualCertStatementsToNss(
	const CE_QC_Statements	 	&cdsaObj,
	NSS_QC_Statements 			&nssObj,
	SecNssCoder 				&coder) 
{
	memset(&nssObj, 0, sizeof(nssObj));
	uint32 numQcs = cdsaObj.numQCStatements;
	nssObj.qcStatements = 
		(NSS_QC_Statement **)clNssNullArray(numQcs, coder);
	for(uint32 dex=0; dex<numQcs; dex++) {
		nssObj.qcStatements[dex] = (NSS_QC_Statement *)
			coder.malloc(sizeof(NSS_QC_Statement));
		NSS_QC_Statement *dst = nssObj.qcStatements[dex];
		CE_QC_Statement *src = &cdsaObj.qcStatements[dex];
		memset(dst, 0, sizeof(*dst));
		coder.allocCopyItem(src->statementId, dst->statementId);
		if(src->semanticsInfo) {
			if(src->otherInfo) {
				/* this is either/or, not both */
				CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
			}

			/* encode this CE_SemanticsInformation */
			CE_SemanticsInformation *srcSI = src->semanticsInfo;
			NSS_SemanticsInformation dstSI;
			memset(&dstSI, 0, sizeof(dstSI));
			if(srcSI->semanticsIdentifier) {
				dstSI.semanticsIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
				coder.allocCopyItem(*srcSI->semanticsIdentifier, 
					*dstSI.semanticsIdentifier);
			}
			if(srcSI->nameRegistrationAuthorities) {
				dstSI.nameRegistrationAuthorities = 
					(NSS_GeneralNames *)coder.malloc(sizeof(NSS_GeneralNames));
				CL_cssmGeneralNamesToNss(*srcSI->nameRegistrationAuthorities,
					*dstSI.nameRegistrationAuthorities, coder);
			}
			PRErrorCode prtn = coder.encodeItem(&dstSI, kSecAsn1SemanticsInformationTemplate, 
				dst->info);
			if(prtn) {
				clErrorLog("CL_cssmQualCertStatementsToNss: encode error\n");
				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
			}
			
		}
		if(src->otherInfo) {
			/* drop in as ASN_ANY */
			coder.allocCopyItem(*src->otherInfo, dst->info);
		}
	}
}
Exemplo n.º 5
0
/*
 * GIven a CSSM_DATA containing a decoded BIT_STRING, 
 * convert to a KeyUsage.
 */
CE_KeyUsage clBitStringToKeyUsage(
	const CSSM_DATA &cdata)
{
	unsigned toCopy = (cdata.Length + 7) / 8;
	if(toCopy > 2) {
		/* I hope I never see this... */
		clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!");
		toCopy = 2;
	}
	unsigned char bits[2] = {0, 0};
	memmove(bits, cdata.Data, toCopy);
	CE_KeyUsage usage = (((unsigned)bits[0]) << 8) | bits[1];
	return usage;
}
/*
 * Encode into a NSS-style Extensions.
 *
 * Each extension object, currently stored as some AsnType subclass,
 * is BER-encoded and the result is stored as an octet string
 * (AsnOcts) in a new Extension object in the TBS.
 *
 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}(). 
 */
void DecodedExtensions::encodeToNss(
	NSS_CertExtension 	**&extensions)
{
	assert(extensions == NULL);

	if(mNumExtensions == 0) {
		/* no extensions, no error */
		return;
	}
	
	/* malloc a NULL_terminated array of NSS_CertExtension pointers */
	unsigned len = (mNumExtensions + 1) * sizeof(NSS_CertExtension *);
	extensions = (NSS_CertExtension **)mCoder.malloc(len);
	memset(extensions, 0, len);
	
	/* grind thru our DecodedExtens, creating an NSS_CertExtension for 
	 * each one */
	for(unsigned extenDex=0; extenDex<mNumExtensions; extenDex++) {
		NSS_CertExtension *thisNssExten = 
			(NSS_CertExtension *)mCoder.malloc(sizeof(NSS_CertExtension));
		memset(thisNssExten, 0, sizeof(NSS_CertExtension));
		extensions[extenDex] = thisNssExten;
		
		const DecodedExten *decodedExt = getExtension(extenDex);
		
		/* BER-encode the extension object if appropriate */
		if(decodedExt->berEncoded()) {
			/* unknown extension type, it's already encoded */
			const CSSM_DATA *srcBer = (const CSSM_DATA *)decodedExt->rawExtn();
			assert(srcBer != NULL);
			mCoder.allocCopyItem(*srcBer, thisNssExten->value);
		}
		else {
			PRErrorCode prtn;
			prtn = mCoder.encodeItem(decodedExt->nssObj(),
				decodedExt->templ(), thisNssExten->value);
			if(prtn) {
				clErrorLog("encodeToNss: extension encode error");
				CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
			}
		}
		ArenaAllocator arenaAlloc(mCoder);
		if(decodedExt->critical()) {
			/* optional, default false */
			clCssmBoolToNss(CSSM_TRUE, thisNssExten->critical, arenaAlloc);
		}
		mCoder.allocCopyItem(decodedExt->extnId(), thisNssExten->extnId);
	}
}
Exemplo n.º 7
0
void CL_encodeDistributionPointName(
	CE_DistributionPointName &cpoint,
	CSSM_DATA &npoint,
	SecNssCoder &coder)
{
	const SecAsn1Template *templ = NULL;
	NSS_GeneralNames gnames;
	NSS_RDN rdn;
	void *encodeSrc = NULL;
	
	/* 
	 * Our job is to convert one of two incoming aggregate types
	 * into NSS format, then encode the result into npoint.
	 */
	switch(cpoint.nameType) {
		case CE_CDNT_FullName:
			CL_cssmGeneralNamesToNss(*cpoint.dpn.fullName,
				gnames, coder);
			encodeSrc = &gnames;
			templ = kSecAsn1DistPointFullNameTemplate;
			break;
			
		case CE_CDNT_NameRelativeToCrlIssuer:
			CL_cssmRdnToNss(*cpoint.dpn.rdn, rdn, coder);
			encodeSrc = &rdn;
			templ = kSecAsn1DistPointRDNTemplate;
			break;
		default:
			clErrorLog("CL_encodeDistributionPointName: bad nameType\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
	}
	if(coder.encodeItem(encodeSrc, templ, npoint)) {
		clErrorLog("CL_encodeDistributionPointName: encode error\n");
		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
	}
}
/* map an OID to an oidToFieldFuncs */
static const oidToFieldFuncs *oidToFields(
	const CssmOid			&fieldId)
{
	const oidToFieldFuncs *fieldTable = fieldFuncTable;
	for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
		if(fieldId == CssmData::overlay(*fieldTable->fieldId)) {
			return fieldTable;
		}
		fieldTable++;
	}
#ifndef	NDEBUG
	clErrorLog("oidToFields: unknown OID (len=%d): %s\n",
		(int)fieldId.length(), fieldId.toHex().c_str());
#endif
	CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
}
/*
 * Obtain the index'th occurrence of field specified by fieldId in specified cert.
 * Format of the returned field depends on fieldId.
 * Returns total number of fieldId fields in the cert if index is 0.
 * FieldValue assumed to be empty on entry.
 * Returns true if specified field was found, else returns false.
 */
bool DecodedCert::getCertFieldData(
	const CssmOid		&fieldId,		// which field
	unsigned			index,			// which occurrence (0 = first)
	uint32				&numFields,		// RETURNED
	CssmOwnedData		&fieldValue) 	// RETURNED
{
	switch(mState) {
		case IS_Empty:
		case IS_Building:
			clErrorLog("DecodedCert::getCertField: can't parse undecoded cert!");
			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
		case IS_DecodedAll:
		case IS_DecodedTBS:
			break;
	}
	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
	return fieldFuncs->getFcn(*this, index, numFields, fieldValue);
}
/* 
 * Given a fully encoded BER object, create a CSSM_X509EXT_TAGandVALUE
 * representing it. We malloc the CSSM_X509EXT_TAGandVALUE itself using 
 * specified allocator, but the referent (in CSSM_X509EXT_TAGandVALUE.value)
 * merely points to data inside the berValue. 
 */
CSSM_X509EXT_TAGandVALUE *DecodedExten::createTagAndValue(
	const CSSM_DATA &berValue,
	Allocator &alloc) const
{
	if((berValue.Data == NULL) || (berValue.Length == 0)) {
		return NULL;
	}
	CSSM_X509EXT_TAGandVALUE *tv = (CSSM_X509EXT_TAGandVALUE *)
		alloc.malloc(sizeof(CSSM_X509EXT_TAGandVALUE));
	tv->type = berValue.Data[0];
	
	/* 
	 * length of length is variable; ASN spec says it can actually be up to  
	 * 127 bytes, but we only have room for 32 bits!
	 */
	const uint8 *lp = berValue.Data + 1;
	uint8 len1 = *lp;
	if((len1 & 0x80) == 0) {
		/* short form */
		tv->value.Length = len1;
		tv->value.Data = const_cast<uint8 *>(lp + 1);
		return tv;
	}
	
	unsigned numLenBytes = len1 & 0x7f;
	if(numLenBytes > 4) {
		clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes);
		alloc.free(tv);
		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
	
	uint32 len = 0;
	lp++;			// points to first length byte
	for(uint32 dex=0; dex<numLenBytes; dex++) {
		len <<= 8;
		len += *lp;
		lp++;
	}
	tv->value.Length = len;
	tv->value.Data = const_cast<uint8 *>(lp);
	return tv;
}
Exemplo n.º 11
0
bool getFieldKeyUsage(
	DecodedItem 		&cert,
	unsigned			index,			// which occurrence (0 = first)
	uint32				&numFields,		// RETURNED
	CssmOwnedData		&fieldValue) 
{
	const DecodedExten *decodedExt;
	CSSM_DATA *nssObj;
	CE_KeyUsage *cdsaObj;
	bool brtn;
	
	brtn = cert.GetExtenTop<CSSM_DATA, CE_KeyUsage>(
		index,
		numFields,
		fieldValue.allocator,
		CSSMOID_KeyUsage,
		nssObj,
		cdsaObj,
		decodedExt);
	if(!brtn) {
		return false;
	}
	
	/* make a copy - can't modify length in place */
	CSSM_DATA bitString = *nssObj;
	clNssBitStringToCssm(bitString);
	size_t toCopy = bitString.Length;
	if(toCopy > 2) {
		/* I hope I never see this... */
		clErrorLog("getFieldKeyUsage: KeyUsage larger than 2 bytes!");
		toCopy = 2;
	}
	unsigned char bits[2] = {0, 0};
	memmove(bits, bitString.Data, toCopy);
	*cdsaObj = (((unsigned)bits[0]) << 8) | bits[1];
	
	/* pass back to caller */
	getFieldExtenCommon(cdsaObj, *decodedExt, fieldValue);
	return true;
}
Exemplo n.º 12
0
/*
 * Common routime to free a CSSM_X509_EXTENSIONS. Used to free 
 * CSSM_X509_TBS_CERTLIST.extensions and 
 * CSSM_X509_REVOKED_CERT_ENTRY.extensions. 
 * We just cook up a CssmOid and a CssmOwnedData for each extension
 * and pass to CL_freeCrlFieldData().
 */
static void CL_freeCssmExtensions(
	CSSM_X509_EXTENSIONS	&extens,
	Allocator			&alloc)
{
	for(uint32 dex=0; dex<extens.numberOfExtensions; dex++) {
		CSSM_X509_EXTENSION_PTR exten = &extens.extensions[dex];
		const CSSM_OID *fieldOid;
		
		/* 
		 * The field OID is either the same as the extension's OID (if we parsed
		 * it) or CSSMOID_X509V3CertificateExtensionCStruct (if we didn't).
		 */
		switch(exten->format) {
			case CSSM_X509_DATAFORMAT_ENCODED:
				fieldOid = &CSSMOID_X509V3CertificateExtensionCStruct;
				break;
			case CSSM_X509_DATAFORMAT_PARSED:
			case CSSM_X509_DATAFORMAT_PAIR:
				fieldOid = &exten->extnId;
				break;
			default:
				clErrorLog("CL_freeCssmExtensions: bad exten->format (%d)",
					(int)exten->format);
				CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
		}
		
		const CssmOid &fieldId = CssmOid::overlay(*fieldOid);
        
        if (exten->extnId.Data != NULL)  // if this is null, something threw when it was instantiated
        {
            CssmData cData((uint8 *)exten, sizeof(CSSM_X509_EXTENSION));
            CssmRemoteData fieldValue(alloc, cData);
            CL_freeCrlFieldData(fieldId, fieldValue, false);
            fieldValue.release();			// but no free (via reset() */
        }
	}
	alloc.free(extens.extensions);
	memset(&extens, 0, sizeof(CSSM_X509_EXTENSIONS));
}
/*
 * Set the field specified by fieldId in the specified Cert.
 * Note no index - individual field routines either append (for extensions)
 * or if field already set ::throwMe(for all others)
 */
void DecodedCert::setCertField(
	const CssmOid		&fieldId,		// which field
	const CssmData		&fieldValue)
{
	switch(mState) {
		case IS_Empty:			// first time thru
			mState = IS_Building;
			break;
		case IS_Building:		// subsequent passes
			break;
		case IS_DecodedAll:
		case IS_DecodedTBS:
			clErrorLog("DecodedCert::setCertField: can't build on a decoded cert!");
			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
	}
	if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
	}
	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
	const CssmData &value = CssmData::overlay(fieldValue);
	fieldFuncs->setFcn(*this, value);
}
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);
	}
}
Exemplo n.º 15
0
bool
AppleX509CLSession::CrlGetNextFieldValue(
	CSSM_HANDLE ResultsHandle,
	CSSM_DATA_PTR &Value)
{
	/* fetch & validate the query */
	CLQuery *query = queryMap.lookupEntry(ResultsHandle);
	if(query == NULL) {
		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
	}
	if(query->queryType() != CLQ_CRL) {
		clErrorLog("CrlGetNextFieldValue: bad queryType (%d)", 
			(int)query->queryType());
		CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE);
	}
	if(query->nextIndex() >= query->numFields()) {
		return false;
	}

	/* fetch the associated cached CRL */
	CLCachedCRL *cachedCrl = lookupCachedCRL(query->cachedObject());
	uint32 dummy;
	CssmAutoData aData(*this);
	if(!cachedCrl->crl().getCrlFieldData(query->fieldId(), 
		query->nextIndex(), 
		dummy,
		aData))  {
		return false;
	}
		
	/* success - copy field data to outgoing Value */
	Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
	*Value = aData.release();
	query->incrementIndex();
	return true;
}
Exemplo n.º 16
0
/* encode TBS component; only called from CertCreateTemplate */
void DecodedCert::encodeTbs(
	CssmOwnedData	&encodedTbs)
{
	encodeExtensions();
	assert(mState == IS_Building);

	/* enforce required fields - could go deeper, maybe we should */
	NSS_TBSCertificate &tbs = mCert.tbs;
	if((tbs.signature.algorithm.Data == NULL) ||
	   (tbs.issuer.rdns == NULL) ||
	   (tbs.subject.rdns == NULL) ||
	   (tbs.subjectPublicKeyInfo.subjectPublicKey.Data == NULL)) {
		clErrorLog("DecodedCert::encodeTbs: incomplete TBS");
		/* an odd, undocumented error return */
		CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES);
	}
	
	PRErrorCode prtn;
	prtn = SecNssEncodeItemOdata(&tbs, kSecAsn1TBSCertificateTemplate,
		encodedTbs);
	if(prtn) {
		CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
	}
}
Exemplo n.º 17
0
/*
 * Obtain a CSSM_KEY from a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO, 
 * inferring as much as we can from required fields 
 * (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) and extensions (for 
 * KeyUse, obtained from the optional DecodedCert).
 */
CSSM_KEY_PTR CL_extractCSSMKeyNSS(
	const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO	&keyInfo,
	Allocator			&alloc,
	const DecodedCert		*decodedCert)			// optional
{
	CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY));
	memset(cssmKey, 0, sizeof(CSSM_KEY));
	CSSM_KEYHEADER &hdr = cssmKey->KeyHeader;
	CssmRemoteData keyData(alloc, cssmKey->KeyData);

	hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
	/* CspId blank */
	hdr.BlobType = CSSM_KEYBLOB_RAW;
	hdr.AlgorithmId = CL_oidToAlg(keyInfo.algorithm.algorithm);
	hdr.KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
	
	/* 
	 * Format inferred from AlgorithmId. I have never seen these defined
	 * anywhere, e.g., what's the format of an RSA public key in a cert?
	 * X509 certainly doesn't say. However. the following two cases are 
	 * known to be correct. 
	 */
	switch(hdr.AlgorithmId) {
		case CSSM_ALGID_RSA:
			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
			break;
		case CSSM_ALGID_DSA:
		case CSSM_ALGID_ECDSA:
		case CSSM_ALGID_DH:
		case CSSM_ALGMODE_PKCS1_EME_OAEP:
			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_X509;
			break;
		case CSSM_ALGID_FEE:
			/* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */
			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
			break;
		default:
			/* punt */
			hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
	}
	hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
	
	/* KeyUsage inferred from extensions */
	if(decodedCert) {
		hdr.KeyUsage = decodedCert->inferKeyUsage();
	}
	else {
		hdr.KeyUsage = CSSM_KEYUSE_ANY;
	}
	
	/* start/end date unknown, leave zero */
	hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
	hdr.WrapMode = CSSM_ALGMODE_NONE;
	
	switch(hdr.AlgorithmId) {
		case CSSM_ALGID_DSA:
		case CSSM_ALGID_ECDSA:
		case CSSM_ALGID_DH:
		case CSSM_ALGMODE_PKCS1_EME_OAEP:
		{
			/* 
			 * Just encode the whole subject public key info blob.
			 * NOTE we're assuming that the keyInfo.subjectPublicKey
			 * field is in the NSS_native BITSTRING format, i.e., 
			 * its Length field is in bits and we don't have to adjust.
			 */
			PRErrorCode prtn = SecNssEncodeItemOdata(&keyInfo, 
				kSecAsn1SubjectPublicKeyInfoTemplate, keyData);
			if(prtn) {
				clErrorLog("extractCSSMKey: error on reencode\n");
				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
			}
			break;
		}
		default:
			/*
			 * RSA, FEE for now.
			 * keyInfo.subjectPublicKey (in BITS) ==> KeyData
			 */
			keyData.copy(keyInfo.subjectPublicKey.Data,
				(keyInfo.subjectPublicKey.Length + 7) / 8);
	}

	/*
	 * LogicalKeySizeInBits - ask the CSP
	 */
	CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true);
	CSSM_KEY_SIZE keySize;
	CSSM_RETURN crtn;
	crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, cssmKey,
		&keySize);
	switch(crtn) {
		default:
			CssmError::throwMe(crtn);
		case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE:
			/*
			 * This is how the CSP indicates a "partial" public key,
			 * with a valid public key value but no alg-specific
			 * parameters (currently, DSA only). 
			 */
			hdr.KeyAttr |= CSSM_KEYATTR_PARTIAL;
			/* and drop thru */
		case CSSM_OK:
			cssmKey->KeyHeader.LogicalKeySizeInBits = 
				keySize.LogicalKeySizeInBits;
			break;
	}

	keyData.release();
	return cssmKey;
}
Exemplo n.º 18
0
void setFieldCertPolicies(		
	DecodedItem	&cert, 
	const CssmData &fieldValue) 
{
	CSSM_X509_EXTENSION_PTR cssmExt = 
		verifySetFreeExtension(fieldValue, false);
	SecNssCoder &coder = cert.coder();
	NSS_CertPolicies *nssObj = 
		(NSS_CertPolicies *)coder.malloc(sizeof(NSS_CertPolicies));
	memset(nssObj, 0, sizeof(NSS_CertPolicies));
	CE_CertPolicies *cdsaObj = 
		(CE_CertPolicies *)cssmExt->value.parsedValue;
	
	if(cdsaObj->numPolicies) {
		nssObj->policies = 
			(NSS_PolicyInformation **)clNssNullArray(
				cdsaObj->numPolicies, coder);
	}
	for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) {
		CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex];
		NSS_PolicyInformation *nPolInfo = (NSS_PolicyInformation *)
			coder.malloc(sizeof(NSS_PolicyInformation));
		memset(nPolInfo, 0, sizeof(*nPolInfo));
		nssObj->policies[polDex] = nPolInfo;
		
		coder.allocCopyItem(cPolInfo->certPolicyId, nPolInfo->certPolicyId);

		unsigned numQual = cPolInfo->numPolicyQualifiers;
		if(numQual != 0) {
			nPolInfo->policyQualifiers = 
				(NSS_PolicyQualifierInfo **)clNssNullArray(numQual,
					coder);
		}
		for(unsigned qualDex=0; qualDex<numQual; qualDex++) {
			CE_PolicyQualifierInfo *cQualInfo = 
				&cPolInfo->policyQualifiers[qualDex];
			NSS_PolicyQualifierInfo *nQualInfo = 
				(NSS_PolicyQualifierInfo *)coder.malloc(
					sizeof(NSS_PolicyQualifierInfo));
			memset(nQualInfo, 0, sizeof(NSS_PolicyQualifierInfo));
			nPolInfo->policyQualifiers[qualDex] = nQualInfo;
			
			/* 
			 * OK we're at the lowest level. 
			 * policyQualifierId == id_qt_cps: qualifier is 
			 * an IA5 string, incoming data is its contents. 
			 * Else incoming data is an encoded blob we pass on directly.
			 */
			coder.allocCopyItem(cQualInfo->policyQualifierId,
				nQualInfo->policyQualifierId);
				
			if(clCompareCssmData(&cQualInfo->policyQualifierId, 
					&CSSMOID_QT_CPS)) {
				if(coder.encodeItem(&cQualInfo->qualifier,
						kSecAsn1IA5StringTemplate,
						nQualInfo->qualifier)) {
					clErrorLog("setFieldCertPOlicies: IA5 encode error\n");
					CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
				}
			}
			else {
				/* uninterpreted, copy over directly */
				coder.allocCopyItem(cQualInfo->qualifier,
					nQualInfo->qualifier);
			}
		}	/* for each qualifier */
	}	/* for each policy */
	
	/* add to mExtensions */
	cert.addExtension(nssObj, cssmExt->extnId, cssmExt->critical, false,
		kSecAsn1CertPoliciesTemplate); 
}
Exemplo n.º 19
0
bool getFieldCertPolicies( 
	DecodedItem 		&cert,
	unsigned			index,			// which occurrence (0 = first)
	uint32				&numFields,		// RETURNED
	CssmOwnedData		&fieldValue) 
{
	const DecodedExten *decodedExt;
	NSS_CertPolicies *nssObj;
	CE_CertPolicies *cdsaObj;
	bool brtn;
	Allocator &alloc = fieldValue.allocator;
	brtn = cert.GetExtenTop<NSS_CertPolicies, CE_CertPolicies>(
		index,
		numFields,
		fieldValue.allocator,
		CSSMOID_CertificatePolicies,
		nssObj,
		cdsaObj,
		decodedExt);
	if(!brtn) {
		return false;
	}
	assert(nssObj != NULL);
	
	memset(cdsaObj, 0, sizeof(*cdsaObj));
	cdsaObj->numPolicies = 
		clNssArraySize((const void **)nssObj->policies);
	unsigned sz = cdsaObj->numPolicies * sizeof(CE_PolicyInformation);
	if(sz) {
		cdsaObj->policies = (CE_PolicyInformation *)alloc.malloc(sz);
		memset(cdsaObj->policies, 0, sz);
	}

	for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) {
		CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex];
		NSS_PolicyInformation *nPolInfo = nssObj->policies[polDex];
		clAllocCopyData(alloc, nPolInfo->certPolicyId,
			cPolInfo->certPolicyId);
		if(nPolInfo->policyQualifiers == NULL) {
			continue;
		}
		
		cPolInfo->numPolicyQualifiers = 
			clNssArraySize((const void **)nPolInfo->policyQualifiers);
		sz = cPolInfo->numPolicyQualifiers * 
			 sizeof(CE_PolicyQualifierInfo);
		cPolInfo->policyQualifiers = (CE_PolicyQualifierInfo *)
			alloc.malloc(sz);
		memset(cPolInfo->policyQualifiers, 0, sz);
		
		for(unsigned qualDex=0; qualDex<cPolInfo->numPolicyQualifiers; 
				qualDex++) {
			NSS_PolicyQualifierInfo *nQualInfo = 
				nPolInfo->policyQualifiers[qualDex];
			CE_PolicyQualifierInfo *cQualInfo = 
				&cPolInfo->policyQualifiers[qualDex];
			
			/* 
			 * leaf. 
			 * policyQualifierId == CSSMOID_QT_CPS : 
			 *  		IA5String - decode and return contents.
			 * Else return whole thing. 
			 */
			clAllocCopyData(alloc, nQualInfo->policyQualifierId,
				cQualInfo->policyQualifierId);
			CSSM_DATA toCopy = nQualInfo->qualifier;
			if(clCompareCssmData(&nQualInfo->policyQualifierId, 
						&CSSMOID_QT_CPS)) {
				/* decode as IA5String to temp memory */
				toCopy.Data = NULL;
				toCopy.Length = 0;
				if(cert.coder().decodeItem(nQualInfo->qualifier,
						kSecAsn1IA5StringTemplate,
						&toCopy)) {
					clErrorLog("***getCertPolicies: bad IA5String!\n");
					CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
				}
			}
			/* else copy out nQualInfo->qualifier */
			clAllocCopyData(alloc, toCopy, cQualInfo->qualifier);
		}	/* for each qualifier */
	}		/* for each policy info */
	getFieldExtenCommon(cdsaObj, *decodedExt, fieldValue);
	return true;
}
Exemplo n.º 20
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);
			}
		}
	}
}
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);
	}
}
/*
 * Initialize by decoding a NSS-style NSS_CertExtension array.
 * This involves figuring out what kind of object is represented in the 
 * octet string in the  extension, decoding it, and appending the resulting 
 * NSS object to mExtensions in the form of a DecodedExten.
 *
 * Called when decoding either a cert or a CRL (for caching it or 
 * getting its fields) or a cert template (only via 
 * CertGetAllTemplateFields()).
 */
void DecodedExtensions::decodeFromNss(
	NSS_CertExtension 	**extensions)	
{
	if(extensions == NULL) {
		/* OK, no extensions present */
		return;
	}
	unsigned numExtens = clNssArraySize((const void **)extensions);

	/* traverse extension list */
	for(unsigned dex=0; dex<numExtens; dex++) {
		NSS_CertExtension *nssExten = extensions[dex];
		
		/*
		 * For this extension->extnId, cook up an appropriate 
		 * NSS-specific type (NSS_KeyUsage, etc.);
		 */
		CSSM_DATA &rawExtn = nssExten->value;
		bool berEncoded = false;
		bool found;								// we understand this OID
		unsigned nssObjLen;						// size of associated NSS object
		const SecAsn1Template *templ = NULL;	// template for decoding
		void *nssObj = NULL;					// decode destination
		found = clOidToNssInfo(nssExten->extnId, nssObjLen, templ);
		if(!found) {
			/* 
			 * We don't know how to deal with this.
			 */
			berEncoded = true;
		}
		else {
			/* 
			 * Create NSS-style object specific to this extension, just
			 * by knowing its length and ASN template. 
			 * Decode the extensions's extnValue into that object. We don't
			 * have to know what kind of object it is anymore. 
			 */
			assert(templ != NULL);
			nssObj = mCoder.malloc(nssObjLen);
			memset(nssObj, 0, nssObjLen);
			PRErrorCode prtn;
			prtn = mCoder.decodeItem(rawExtn, templ, nssObj); 
			if(prtn) {
				/* 
				 * FIXME - what do we do here? For now flag it 
				 * as an non-understood extension...
				 */
				clErrorLog("decodeExtensions: extension decode error\n");
				nssObj = NULL;
				berEncoded = true;
			}
		}	
		if((nssObj != NULL) || berEncoded) {
			/* append if the decode was successful */
			addExtension(nssExten->extnId,
				clNssBoolToCssm(nssExten->critical),
				nssObj, 
				berEncoded,
				templ,
				&rawExtn);
		}
	}
}
/*
 * Common means to get all fields from a decoded cert. Used in
 * CertGetAllTemplateFields and CertGetAllFields.
 */
void DecodedCert::getAllParsedCertFields(
	uint32 				&NumberOfFields,		// RETURNED
	CSSM_FIELD_PTR 		&CertFields)			// RETURNED
{
	/* this is the max - some might be missing */
	uint32 maxFields = NUM_STD_CERT_FIELDS + mDecodedExtensions.numExtensions();
	CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(maxFields * sizeof(CSSM_FIELD));

	/*
	 * We'll be copying oids and values for fields we find into
	 * outFields; current number of valid fields found in numOutFields.
	 */
	memset(outFields, 0, maxFields * sizeof(CSSM_FIELD));
	uint32 			numOutFields = 0;
	CSSM_FIELD_PTR 	currOutField;
	uint32 			currOidDex;
	const CSSM_OID 	*currOid;
	CssmAutoData 	aData(mAlloc);		// for malloc/copy of outgoing data

	/* query for each OID we know about */
	for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) {
		const oidToFieldFuncs *fieldFuncs = &fieldFuncTable[currOidDex];
		currOid = fieldFuncs->fieldId;
		uint32 numFields;				// for THIS oid

		/*
		 * Return false if field not there, which is not an error here.
		 * Actual exceptions are fatal.
		 */
		if(!fieldFuncs->getFcn(*this,
				0, 				// index - looking for first one
				numFields,
				aData)) {
			continue;
		}

		/* got some data for this oid - copy it and oid to outgoing CertFields */
		assert(numOutFields < maxFields);
		currOutField = &outFields[numOutFields];
		currOutField->FieldValue = aData.release();
		aData.copy(*currOid);
		currOutField->FieldOid = aData.release();
		numOutFields++;

		/* if more fields are available for this OID, snag them too */
		for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) {
			/* note this should always succeed */
			bool brtn = fieldFuncs->getFcn(*this,
				fieldDex,
				numFields, 			// shouldn't change
				aData);
			if(!brtn) {
				clErrorLog("getAllParsedCertFields: index screwup");
				CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
			}
			assert(numOutFields < maxFields);
			currOutField = &outFields[numOutFields];
			currOutField->FieldValue = aData.release();
			aData.copy(*currOid);
			currOutField->FieldOid = aData.release();
			numOutFields++;
		}	/* multiple fields for currOid */
	}		/* for each known OID */

	NumberOfFields = numOutFields;
	CertFields = outFields;
}
void CL_cssmGeneralNameToNss(
	CE_GeneralName &cdsaObj,
	NSS_GeneralName &nssObj,		// actually an NSSTaggedItem
	SecNssCoder &coder)				// for temp decoding
{
	memset(&nssObj, 0, sizeof(nssObj));
	
	/*
	 * The default here is just to use the app-supplied data as is...
	 */
	nssObj.item = cdsaObj.name;
	unsigned char itemTag;			// for nssObj.tag
	bool doCopy = false;			// unless we have to modify tag byte
	unsigned char overrideTag;		// to force context-specific tag for
									//   an ASN_ANY
	PRErrorCode prtn;
									
	switch(cdsaObj.nameType) {
		case GNT_OtherName:	
			/*
			 * Caller supplies an CE_OtherName. Encode it.
			 */
			if((cdsaObj.name.Length != sizeof(CE_OtherName)) ||
			   (cdsaObj.name.Data == NULL)) {
				clErrorLog("CL_cssmGeneralNameToNss: OtherName.Length"
					" error\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			prtn = coder.encodeItem(cdsaObj.name.Data,
				kSecAsn1OtherNameTemplate, nssObj.item);
			if(prtn) {
				clErrorLog("CL_cssmGeneralNameToNss: OtherName encode"
					" error\n");
				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
			}
			itemTag = NGT_OtherName;
			break;
		case GNT_RFC822Name:		// IA5String
			itemTag = NGT_RFC822Name;
			break;
		case GNT_DNSName:			// IA5String
			itemTag = NGT_DNSName;
			break;
		case GNT_X400Address:		// caller's resposibility
			/*
			 * Encoded as ASN_ANY, the only thing we do is to 
			 * force the correct context-specific tag
			 */
			itemTag = GNT_X400Address;
			if(!cdsaObj.berEncoded) {
				clErrorLog("CL_cssmGeneralNameToNss: X400Address must"
					" be BER-encoded\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}			
			overrideTag = SEC_ASN1_CONTEXT_SPECIFIC | 
				SEC_ASN1_CONSTRUCTED | NGT_X400Address;
			doCopy = true;
			break;
		case GNT_DirectoryName:	
		{
			/*
			 * Caller supplies an CSSM_X509_NAME. Convert to NSS
			 * format and encode it.
			 */
			if((cdsaObj.name.Length != sizeof(CSSM_X509_NAME)) || 
			   (cdsaObj.name.Data == NULL)) {
				clErrorLog("CL_cssmGeneralNameToNss: DirectoryName.Length"
					" error\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			NSS_Name nssName;
			CSSM_X509_NAME_PTR cdsaName = 
				(CSSM_X509_NAME_PTR)cdsaObj.name.Data;
			CL_cssmNameToNss(*cdsaName, nssName, coder);
			prtn = coder.encodeItem(&nssName,
				kSecAsn1NameTemplate, nssObj.item);
			if(prtn) {
				clErrorLog("CL_cssmGeneralNameToNss: X509Name encode"
					" error\n");
				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
			}
			itemTag = GNT_DirectoryName;
			
			/*
			 * AND, munge the tag to make it a context-specific
			 * sequence
			 * no, not needed, this is wrapped in an explicit...
			 */
			//nssObj.item.Data[0] = SEC_ASN1_CONTEXT_SPECIFIC | 
			//	SEC_ASN1_CONSTRUCTED | GNT_DirectoryName;

			break;
		}
		case GNT_EdiPartyName:		// caller's resposibility
			/*
			 * Encoded as ASN_ANY, the only thing we do is to 
			 * force the correct context-specific tag
			 */
			itemTag = GNT_EdiPartyName;
			if(!cdsaObj.berEncoded) {
				clErrorLog("CL_cssmGeneralNameToNss: EdiPartyName must"
					" be BER-encoded\n");
				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
			}
			overrideTag = SEC_ASN1_CONTEXT_SPECIFIC |  NGT_X400Address;
			doCopy = true;
			break;
		case GNT_URI:				// IA5String
			itemTag = GNT_URI;
			break;
		case GNT_IPAddress:			// OCTET_STRING
			itemTag = NGT_IPAddress;
			break;
		case GNT_RegisteredID:		// OID
			itemTag = NGT_RegisteredID;
			break;
		default:
			clErrorLog("CL_cssmGeneralNameToNss: bad name tag\n");
			CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
	}
	if(doCopy) {
		coder.allocCopyItem(cdsaObj.name, nssObj.item);
		nssObj.item.Data[0] = overrideTag;
	}
	nssObj.tag = itemTag;
}