DecodedExten::DecodedExten(
	const CSSM_OID 	&extnId,	// copied
	bool			critical,
	void			*nssObj,	// NSS_KeyUsage, NSS_BasicConstraints, 
								//   etc. NOT COPIED, exists in same
								//   memory space as coder
	bool			berEncoded,	// indicates unknown extension which we
								// do not BER-decode when parsing a cert
	const SecAsn1Template *templ,	// to decode/encode if !berEncoded
	SecNssCoder		&coder,			// all local allocs from here
	const CSSM_DATA	*rawExtn)	// NSS_CertExtension.value, copied to
								//   mRawExtn
	: mCritical(critical),
	  mNssObj(nssObj),
	  mBerEncoded(berEncoded),
	  mTempl(templ),
	  mCoder(coder),
	  mRawExtn(NULL)
{
	coder.allocCopyItem(extnId, mExtnId);
	if(rawExtn) {
		mRawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
		coder.allocCopyItem(*rawExtn, *mRawExtn);
	}
}
void CL_cssmInfoAccessToNss(
	const CE_AuthorityInfoAccess	&cdsaObj,
	NSS_AuthorityInfoAccess			&nssObj,
	SecNssCoder						&coder)  
{
	memset(&nssObj, 0, sizeof(nssObj));
	uint32 numDescs = cdsaObj.numAccessDescriptions;
	nssObj.accessDescriptions = (NSS_AccessDescription **)clNssNullArray(numDescs, coder);
	
	for(unsigned dex=0; dex<numDescs; dex++) {
		nssObj.accessDescriptions[dex] = coder.mallocn<NSS_AccessDescription>();
		CE_AccessDescription *src = &cdsaObj.accessDescriptions[dex];
		NSS_AccessDescription *dst = nssObj.accessDescriptions[dex];
		coder.allocCopyItem(src->accessMethod, dst->accessMethod);
		
		/* Convert general name, then encode it into destination */
		NSS_GeneralName nssGenName;
		CL_cssmGeneralNameToNss(src->accessLocation, nssGenName, coder);
		PRErrorCode prtn = coder.encodeItem(&nssGenName, kSecAsn1GeneralNameTemplate, 
			dst->encodedAccessLocation);
		if(prtn) {
			clErrorLog("CL_cssmInfoAccessToNss: encode error\n");
			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
		}
	}
}
void CL_certCrlDecodeComponents(
	const CssmData 	&signedItem,		// DER-encoded cert or CRL
	CssmOwnedData	&tbsBlob,			// still DER-encoded
	CssmOwnedData	&algId,				// ditto
	CssmOwnedData	&rawSig)			// raw bits (not an encoded AsnBits)
{
	/* BER-decode into temp memory */
	NSS_SignedCertOrCRL nssObj;
	SecNssCoder coder;
	PRErrorCode prtn;
	
	memset(&nssObj, 0, sizeof(nssObj));
	prtn = coder.decode(signedItem.data(), signedItem.length(),
		kSecAsn1SignedCertOrCRLTemplate, &nssObj);
	if(prtn) {
		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
	}
	
	/* tbsBlob and algId are raw ASN_ANY including tags, which we pass 
	 * back to caller intact */
	tbsBlob.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length);
	algId.copy(nssObj.signatureAlgorithm.Data, 
		nssObj.signatureAlgorithm.Length);
		
	/* signature is a bit string which we do in fact decode */
	rawSig.copy(nssObj.signature.Data,
		(nssObj.signature.Length + 7) / 8);
}
void CL_cssmGeneralNamesToNss(
	const CE_GeneralNames &cdsaObj, 
	NSS_GeneralNames &nssObj,
	SecNssCoder &coder)
{
	uint32 numNames = cdsaObj.numNames;
	nssObj.names = (CSSM_DATA **)clNssNullArray(numNames, coder);
	
	/* 
	 * Convert each element in cdsaObj to NSS form, encode, drop into
	 * the ASN_ANY array.
	 *
	 * 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);
	for(unsigned dex=0; dex<cdsaObj.numNames; dex++) {
		nssObj.names[dex] = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
		memset(nssObj.names[dex], 0, sizeof(CSSM_DATA));
		CL_cssmGeneralNameToNss(cdsaObj.generalName[dex],
			names[dex], coder);
		if(coder.encodeItem(&names[dex], kSecAsn1GeneralNameTemplate,
				*nssObj.names[dex])) {
			clErrorLog("***Error encoding General.name\n");
			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
		}
	}
}
/* 
 * 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;
	}
}
/* 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);
	}
}
/* 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();
	}
}
/* 
 * CSSM_X509_TYPE_VALUE_PAIR --> NSS_ATV 
 */
void CL_cssmAtvToNss(
	const CSSM_X509_TYPE_VALUE_PAIR	&cssmObj,
	NSS_ATV							&nssObj,
	SecNssCoder						&coder)
{
	memset(&nssObj, 0, sizeof(nssObj));
	
	/* copy the OID */
	coder.allocCopyItem(cssmObj.type, nssObj.type);
	
	/* tag and value */
	nssObj.value.tag = cssmObj.valueType;
	coder.allocCopyItem(cssmObj.value, nssObj.value.item);
}
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;
	}
}
Example #10
0
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);
	}
}
Example #11
0
/* 
 * 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);
	}
}
/*
 * 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;
	}
}
/* uint32 --> CSSM_DATA */
void p12IntToData(
	uint32 num,
	CSSM_DATA &cdata,
	SecNssCoder &coder)
{
	uint32 len = 0;
	
	if(num < 0x100) {
		len = 1;
	}
	else if(num < 0x10000) {
		len = 2;
	}
	else if(num < 0x1000000) {
		len = 3;
	}
	else {
		len = 4;
	}
	coder.allocItem(cdata, len);
	uint8 *cp = &cdata.Data[len - 1];
	for(unsigned i=0; i<len; i++) {
		*cp-- = num & 0xff;
		num >>= 8;
	}
}
/*
 * Calculate the MAC for a PFX. Caller is either going compare
 * the result against an existing PFX's MAC or drop the result into 
 * a newly created PFX.
 */
CSSM_RETURN p12GenMac(
	CSSM_CSP_HANDLE		cspHand,
	const CSSM_DATA		&ptext,	// e.g., NSS_P12_DecodedPFX.derAuthSaafe
	CSSM_ALGORITHMS		alg,	// better be SHA1!
	unsigned			iterCount,
	const CSSM_DATA		&salt,
	/* exactly one of the following two must be valid */
	const CSSM_DATA		*pwd,		// unicode external representation
	const CSSM_KEY		*passKey,
	SecNssCoder			&coder,		// for mallocing macData
	CSSM_DATA			&macData)	// RETURNED 
{
	CSSM_RETURN crtn;
	CSSM_CC_HANDLE ccHand = 0;
	
	/* P12 style key derivation */
	unsigned keySizeInBits;
	CSSM_ALGORITHMS hmacAlg;
	switch(alg) {
		case CSSM_ALGID_SHA1:
			keySizeInBits = 160;
			hmacAlg = CSSM_ALGID_SHA1HMAC;
			break;
		case CSSM_ALGID_MD5:
			/* not even sure if this is legal in p12 world... */
			keySizeInBits = 128;
			hmacAlg = CSSM_ALGID_MD5HMAC;
			break;
		default:
			return CSSMERR_CSP_INVALID_ALGORITHM;
	}
	CSSM_KEY macKey;
	CSSM_DATA iv = {0, NULL};
	crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg,
		keySizeInBits, iterCount, salt, pwd, passKey, iv);
	if(crtn) {
		return crtn;
	}	
	/* subsequent errors to errOut: */

	/* prealloc the mac data */
	coder.allocItem(macData, keySizeInBits / 8);
	crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand);
	if(crtn) {
		cuPrintError("CSSM_CSP_CreateMacContext", crtn);
		goto errOut;
	}
	
	crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData);
	if(crtn) {
		cuPrintError("CSSM_GenerateMac", crtn);
	}
errOut:
	if(ccHand) {
		CSSM_DeleteContext(ccHand);
	}
	CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE);
	return crtn;
}
Example #15
0
/* 
 * CSSM time to NSS time. 
 */
void CL_cssmTimeToNss(
	const CSSM_X509_TIME &cssmTime, 
	NSS_TaggedItem &nssTime, 
	SecNssCoder &coder)
{
	nssTime.tag = cssmTime.timeType;
	coder.allocCopyItem(cssmTime.time, nssTime.item);
}
void p12CfDataToCssm(
	CFDataRef cf,
	CSSM_DATA &c,
	SecNssCoder &coder)
{
	coder.allocCopyItem(CFDataGetBytePtr(cf),
		CFDataGetLength(cf), c);
}
void p12GenSalt(
	CSSM_DATA &salt,
	SecNssCoder &coder)
{
	DevRandomGenerator rng;
	coder.allocItem(salt, P12_SALT_LEN);
	rng.random(salt.Data, P12_SALT_LEN);
}
Example #18
0
void CL_cssmAuthorityKeyIdToNss(
	const CE_AuthorityKeyID 	&cdsaObj,
	NSS_AuthorityKeyId 			&nssObj,
	SecNssCoder 				&coder) 
{
	memset(&nssObj, 0, sizeof(nssObj));
	if(cdsaObj.keyIdentifierPresent) {
		nssObj.keyIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
		coder.allocCopyItem(cdsaObj.keyIdentifier, *nssObj.keyIdentifier);
	}
	if(cdsaObj.generalNamesPresent ) {
		/* GeneralNames, the hard one */
		CL_cssmGeneralNamesToNss(*cdsaObj.generalNames,
			nssObj.genNames, coder);
	}
	if(cdsaObj.serialNumberPresent) {
		coder.allocCopyItem(cdsaObj.serialNumber,nssObj.serialNumber);
	}
}
Example #19
0
void CL_cssmDistPointsToNss(
	const CE_CRLDistPointsSyntax 	&cdsaObj,
	NSS_CRLDistributionPoints		&nssObj,
	SecNssCoder 					&coder)
{
	memset(&nssObj, 0, sizeof(nssObj));
	unsigned numPoints = cdsaObj.numDistPoints;
	if(numPoints == 0) {
		return;
	}
	nssObj.distPoints = 
		(NSS_DistributionPoint **)clNssNullArray(numPoints, coder);
	for(unsigned dex=0; dex<numPoints; dex++) {
		nssObj.distPoints[dex] = (NSS_DistributionPoint *)
			coder.malloc(sizeof(NSS_DistributionPoint));
		NSS_DistributionPoint *npoint = nssObj.distPoints[dex];
		memset(npoint, 0, sizeof(NSS_DistributionPoint));
		CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex];
		
		/* all fields are optional */
		if(cpoint->distPointName) {
			/* encode and drop into ASN_ANY slot */
			npoint->distPointName = (CSSM_DATA *)
				coder.malloc(sizeof(CSSM_DATA));
			CL_encodeDistributionPointName(*cpoint->distPointName,
				*npoint->distPointName, coder);
			
		}
		
		if(cpoint->reasonsPresent) {
			/* bit string, presumed max length 8 bits */
			coder.allocItem(npoint->reasons, 1);
			npoint->reasons.Data[0] = cpoint->reasons;
			/* adjust for bit string length */
			npoint->reasons.Length = 8;
		}
		
		if(cpoint->crlIssuer) {
			CL_cssmGeneralNamesToNss(*cpoint->crlIssuer,
				npoint->crlIssuer, coder);
		}
	}
}
/* CSSM_X509_RDN --> NSS_RDN */
void CL_cssmRdnToNss(
	const CSSM_X509_RDN	&cssmObj,
	NSS_RDN				&nssObj,
	SecNssCoder			&coder)
{
	memset(&nssObj, 0, sizeof(nssObj));
	
	/* alloc NULL-terminated array of ATV pointers */
	unsigned numAtvs = cssmObj.numberOfPairs;
	unsigned size = (numAtvs + 1) * sizeof(void *);
	nssObj.atvs = (NSS_ATV **)coder.malloc(size);
	memset(nssObj.atvs, 0, size);
	
	/* grind thru the elements */
	for(unsigned atvDex=0; atvDex<numAtvs; atvDex++) {
		nssObj.atvs[atvDex] = (NSS_ATV *)coder.malloc(sizeof(NSS_ATV));
		CL_cssmAtvToNss(cssmObj.AttributeTypeAndValue[atvDex],
			*nssObj.atvs[atvDex], coder);
	}
}
/*
 * 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;
		}
	}
}
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);
	}
}
Example #23
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);
		}
	}
}
/* convert App passphrase to array of chars used in P12 PBE */
void p12ImportPassPhrase(
	CFStringRef		inPhrase,
	SecNssCoder		&coder,
	CSSM_DATA		&outPhrase)
{
	CFDataRef cfData = CFStringCreateExternalRepresentation(NULL,
		inPhrase, kCFStringEncodingUTF8, 0);
	if(cfData == NULL) {
		p12ErrorLog("***p12ImportPassPhrase: can't convert passphrase to UTF8\n");
		MacOSError::throwMe(errSecParam);
	}
	CFIndex keyLen = CFDataGetLength(cfData);
	coder.allocItem(outPhrase, keyLen);
	memmove(outPhrase.Data, CFDataGetBytePtr(cfData), keyLen);
	CFRelease(cfData);
}
/* 
 * Generate random label string to allow associating an imported private
 * key with a cert.
 */
void p12GenLabel(
	CSSM_DATA &label,
	SecNssCoder &coder)
{
	/* first a random uint32 */
	uint8 d[4];
	DevRandomGenerator rng;
	rng.random(d, 4);
	CSSM_DATA cd = {4, d};
	uint32 i;
	p12DataToInt(cd, i);
	
	/* sprintf that into a real string */
	coder.allocItem(label, 9);
	memset(label.Data, 0, 9);
	sprintf((char *)label.Data, "%08X", (unsigned)i);
}
/* CSSM_X509_NAME --> NSS_Name */
void CL_cssmNameToNss(
	const CSSM_X509_NAME	&cssmObj,
	NSS_Name				&nssObj,
	SecNssCoder				&coder)
{
	memset(&nssObj, 0, sizeof(nssObj));
	
	/* alloc NULL-terminated array of RDN pointers */
	unsigned numRdns = cssmObj.numberOfRDNs;
	nssObj.rdns = (NSS_RDN **)clNssNullArray(numRdns, coder);
	
	/* grind thru the elements */
	for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
		nssObj.rdns[rdnDex] = (NSS_RDN *)coder.malloc(sizeof(NSS_RDN));
		CL_cssmRdnToNss(cssmObj.RelativeDistinguishedName[rdnDex],
			*nssObj.rdns[rdnDex], coder);
	}
}
/*
 * Attempt to convert a CFStringRef, which represents a SafeBag's
 * FriendlyName, to a UTF8-encoded CSSM_DATA. The CSSM_DATA and its
 * referent are allocated in the specified SecNssCoder's memory.
 * No guarantee that this conversion works. If it doesn't we return 
 * NULL and caller must be prepared to deal with that. 
 */
CSSM_DATA_PTR p12StringToUtf8(
	CFStringRef cfStr,
	SecNssCoder &coder)
{
	if(cfStr == NULL) {
		return NULL;
	}
	CFIndex strLen = CFStringGetLength(cfStr);
	if(strLen == 0) {
		return NULL;
	}
	CSSM_DATA_PTR rtn = coder.mallocn<CSSM_DATA>();
	coder.allocItem(*rtn, strLen + 1);
	if(!CFStringGetCString(cfStr, (char *)rtn->Data,strLen + 1,
			kCFStringEncodingUTF8)) {
		/* not convertible from native Unicode to UTF8 */
		return NULL;
	}
	return rtn;
}
/*
 * 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);
	}
}
Example #29
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);
	}
}
/*
 * Given an array of PEM parameter lines, infer parameters for key derivation and 
 * encryption.
 */
static OSStatus opensslPbeParams(
	CFArrayRef			paramLines,			// elements are CFStrings
	SecNssCoder			&coder,				// IV allocd with this
	/* remaining arguments RETURNED */
	CSSM_ALGORITHMS		&pbeAlg,
	CSSM_ALGORITHMS		&keyAlg,
	CSSM_ALGORITHMS		&encrAlg,
	CSSM_ENCRYPT_MODE	&encrMode,
	CSSM_PADDING		&encrPad,
	uint32				&keySizeInBits,
	unsigned			&blockSizeInBytes,
	CSSM_DATA			&iv)
{
	/* 
	 * This format requires PEM parameter lines. We could have gotten here
	 * without them if caller specified wrong format.
	 */
	 if(paramLines == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: no PEM parameter lines");
		return errSecUnknownFormat;
	 }
	 CFStringRef dekInfo = NULL;
	 CFIndex numLines = CFArrayGetCount(paramLines);
	 for(CFIndex dex=0; dex<numLines; dex++) {
		CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(paramLines, dex);
		CFRange range;
		range = CFStringFind(str, CFSTR("DEK-Info: "), 0);
		if(range.length != 0) {
			dekInfo = str;
			break;
		}
	 }
	 if(dekInfo == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: no DEK-Info lines");
		return errSecUnknownFormat;
	 }
	 
	 /* drop down to C strings for low level grunging */
	 char cstr[1024];
	 if(!CFStringGetCString(dekInfo, cstr, sizeof(cstr), kCFStringEncodingASCII)) {
		SecImpExpDbg("importWrappedKeyOpenssl: bad DEK-Info line (1)");
		return errSecUnknownFormat;
	 }
	 
	/* 
	 * This line looks like this:
	 * DEK-Info: DES-CBC,A22977A0A6A6F696
	 * 
	 * Now parse, getting the cipher spec and the IV.
	 */
	char *cp = strchr(cstr, ':');
	if(cp == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: bad DEK-Info line (2)");
		return errSecUnknownFormat;
	}
	if((cp[1] == ' ') && (cp[2] != '\0')) {
		/* as it normally does... */
		cp += 2;
	}
	
	/* We only support DES and 3DES here */
	if(!strncmp(cp, "DES-EDE3-CBC", 12)) {
		keyAlg = CSSM_ALGID_3DES_3KEY;
		encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
		keySizeInBits = 64 * 3;
		blockSizeInBytes = 8;
	}
	else if(!strncmp(cp, "DES-CBC", 7)) {
		keyAlg = CSSM_ALGID_DES;
		encrAlg = CSSM_ALGID_DES;
		keySizeInBits = 64;
		blockSizeInBytes = 8;
	}
	else {
		SecImpExpDbg("importWrappedKeyOpenssl: unrecognized wrap alg (%s)",
			cp);
		return errSecUnknownFormat;
	}

	/* these are more or less fixed */
	pbeAlg   = CSSM_ALGID_PBE_OPENSSL_MD5;
	encrMode = CSSM_ALGMODE_CBCPadIV8;
	encrPad  = CSSM_PADDING_PKCS7;
	
	/* now get the ASCII hex version of the IV */
	cp = strchr(cp, ',');
	if(cp == NULL) {
		SecImpExpDbg("importWrappedKeyOpenssl: No IV in DEK-Info line");
		return errSecUnknownFormat;
	}
	if(cp[1] != '\0') {
		cp++;
	}
	
	/* remainder should be just the IV */
	if(strlen(cp) != (blockSizeInBytes * 2)) {
		SecImpExpDbg("importWrappedKeyOpenssl: bad IV in DEK-Info line (1)");
		return errSecUnknownFormat;
	}
	
	coder.allocItem(iv, blockSizeInBytes);
	for(unsigned dex=0; dex<blockSizeInBytes; dex++) {
		if(hexToUchar(cp + (dex * 2), &iv.Data[dex])) {
			SecImpExpDbg("importWrappedKeyOpenssl: bad IV in DEK-Info line (2)");
			return errSecUnknownFormat;
		}
	}
	return errSecSuccess;
}