/*
 * CertBag via SEC_ASN1_DYNAMIC
 */
static const SecAsn1Template * NSS_P12_CertBagChooser(
	void *arg, 			// --> NSS_P12_CertBag
	Boolean enc,
	const char *buf,	// on decode, tag byte
	void *dest)			// --> NSS_P12_CertBag.bagValue
{
	NSS_P12_CertBag *bag = (NSS_P12_CertBag *)arg;
	const SecAsn1Template *templ = NULL;
	NSS_P12_CertBagType type = CT_Unknown;
	CSSM_OID *oid = &bag->bagType;
	
	if(nssCompareCssmData(oid, &CSSMOID_PKCS9_X509Certificate)) {
		templ = kSecAsn1OctetStringTemplate;
		type = CT_X509;
	}
	else if(nssCompareCssmData(oid, &CSSMOID_PKCS9_SdsiCertificate)) {
		templ = kSecAsn1IA5StringTemplate;
		type = CT_SDSI;
	}
	else {
		/* punt */
		templ = kSecAsn1AnyTemplate;
	}
	if(!enc) {
		bag->type = type;
	}
	return templ;
}
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;
	}
}
/* 
 * NOTE: as of March 8 2004 this is also used by the SecImportExport
 * module...not just PKCS12!
 */
bool pkcsOidToParams(
	const CSSM_OID 		*oid,
	CSSM_ALGORITHMS		&keyAlg,		// e.g., CSSM_ALGID_DES
	CSSM_ALGORITHMS		&encrAlg,		// e.g., CSSM_ALGID_3DES_3KEY_EDE
	CSSM_ALGORITHMS		&pbeHashAlg,	// SHA1 or MD5
	uint32				&keySizeInBits,
	uint32				&blockSizeInBytes,	// for IV, optional
	CSSM_PADDING		&padding,		// CSSM_PADDING_PKCS7, etc.
	CSSM_ENCRYPT_MODE	&mode,			// CSSM_ALGMODE_CBCPadIV8, etc.
	PKCS_Which			&pkcs)			// PW_PKCS5_v1_5 or PW_PKCS12
{
	const PKCSOidInfo *info = pkcsOidInfos;
	pkcs = PW_None;
	
	for(unsigned dex=0; dex<NUM_PKCS_OID_INFOS; dex++) {
		if(nssCompareCssmData(oid, info->oid)) {
			keyAlg 			 = info->keyAlg;
			encrAlg 		 = info->encrAlg;
			pbeHashAlg 		 = info->pbeHashAlg;
			keySizeInBits 	 = info->keySizeInBits;
			blockSizeInBytes = info->blockSizeInBytes;
			padding			 = info->padding;
			mode 			 = info->mode;
			pkcs			 = info->pkcs;
			return true;
		}
		info++;
	}
	return false;
}
static int attrParse(
	const NSS_Attribute *attr,
	P12ParseInfo &pinfo, 
	unsigned depth)
{
	doIndent(depth);
	printf("attrType : %s\n", oidStr(attr->attrType, pinfo.mParser));
	unsigned numVals = nssArraySize((const void **)attr->attrValue);
	doIndent(depth);
	printf("numValues = %u\n", numVals);

	for(unsigned dex=0; dex<numVals; dex++) {
		doIndent(depth);
		printf("val[%u] : ", dex);
		
		/*
		 * Note: these two enumerated types should only have one att value 
		 * per PKCS9. Leave that to real apps, we want to see what's there
		 * in any case.
		 */
		if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_FriendlyName)) {
			/* BMP string (UniCode) */
			CSSM_DATA ustr;
			if(pinfo.mCoder.decodeItem(*attr->attrValue[dex],
					kSecAsn1BMPStringTemplate, &ustr)) {
				printf("***Error decoding BMP string\n");
				continue;
			}
			printDataAsUnichars(ustr);
		}
		else if(nssCompareCssmData(&attr->attrType, 
					&CSSMOID_PKCS9_LocalKeyId)) {
			/* Octet string */
			CSSM_DATA ostr;
			if(pinfo.mCoder.decodeItem(*attr->attrValue[dex],
					kSecAsn1ObjectIDTemplate, &ostr)) {
				printf("***Error decoding LocalKeyId string\n");
				continue;
			}
			printDataAsHex(&ostr, 16);
		}
		else {
			printDataAsHex(attr->attrValue[dex], 8);
		}
	}
	return 0;
}
static int p12Parse(
	const CSSM_DATA &rawBlob, 
	P12ParseInfo &pinfo,
	unsigned depth)		// print indent depth
{
	NSS_P12_DecodedPFX pfx;
	memset(&pfx, 0, sizeof(pfx));
	if(pinfo.mCoder.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) {
		printf("***Error on top-level decode of NSS_P12_DecodedPFX\n");
		return 1;
	}
	doIndent(depth);
	printf("version = %u\n", (unsigned)dataToInt(pfx.version));
	NSS_P7_DecodedContentInfo &dci = pfx.authSafe;

	doIndent(depth);
	printf("contentType = %s\n", oidStr(dci.contentType, pinfo.mParser));
	doIndent(depth);
	printf("type = %s\n", p7ContentInfoTypeStr(dci.type));
	int rtn = 0;
	if(nssCompareCssmData(&dci.contentType, &CSSMOID_PKCS7_Data)) {
		doIndent(depth);
		printf("AuthenticatedSafe Length %u {\n", 
			(unsigned)dci.content.data->Length);
		rtn = authSafeParse(*dci.content.data, pinfo, depth+3);
		doIndent(depth);
		printf("}\n");
	}
	else {
		printf("Not parsing any other content type today.\n");
	}
	if(pfx.macData) {
		doIndent(depth);
		printf("Mac Data {\n");
		p12MacParse(*pfx.macData, pinfo, depth+3);
		doIndent(depth);
		printf("}\n");
		if(pinfo.mPwd.Data == NULL) {
			doIndent(depth);
			printf("=== MAC not verified (no passphrase)===\n");
		}
		else {
			CSSM_RETURN crtn = p12VerifyMac_app(pfx, pinfo.mCspHand, 
				pinfo.mPwd, pinfo.mCoder);
			doIndent(depth);
			if(crtn) {
				cssmPerror("p12VerifyMac", crtn);
				doIndent(depth);
				printf("***MAC verify failure.\n");
			}
			else {
				printf("MAC verifies OK.\n");
			}
		}
	}
	return 0;
}
/*
 * Verify MAC on an existing PFX.  
 */
CSSM_RETURN p12VerifyMac(
	const NSS_P12_DecodedPFX 	&pfx,
	CSSM_CSP_HANDLE				cspHand,
	const CSSM_DATA				*pwd,	// unicode, double null terminated
	const CSSM_KEY				*passKey,
	SecNssCoder					&coder)	// for temp mallocs
{
	if(pfx.macData == NULL) {
		return CSSMERR_CSP_INVALID_SIGNATURE;
	}
	NSS_P12_MacData &macData = *pfx.macData;
	NSS_P7_DigestInfo &digestInfo  = macData.mac;
	CSSM_OID &algOid = digestInfo.digestAlgorithm.algorithm;
	CSSM_ALGORITHMS macAlg;
	if(!cssmOidToAlg(&algOid, &macAlg)) {
		return CSSMERR_CSP_INVALID_ALGORITHM;
	}
	uint32 iterCount = 0;
	CSSM_DATA &citer = macData.iterations;
	if(!p12DataToInt(citer, iterCount)) {
		return CSSMERR_CSP_INVALID_ATTR_ROUNDS;
	}
	if(iterCount == 0) {
		/* optional, default 1 */
		iterCount = 1;
	}

	/*
	 * In classic fashion, the PKCS12 spec now says:
	 *
	 *      When password integrity mode is used to secure a PFX PDU, 
	 *      an SHA-1 HMAC is computed on the BER-encoding of the contents 
	 *      of the content field of the authSafe field in the PFX PDU.
	 *
	 * So here we go.
	 */
	CSSM_DATA genMac;
	CSSM_RETURN crtn = p12GenMac(cspHand, *pfx.authSafe.content.data, 
		macAlg, iterCount, macData.macSalt, pwd, passKey, coder, genMac);
	if(crtn) {
		return crtn;
	}
	if(nssCompareCssmData(&genMac, &digestInfo.digest)) {
		return CSSM_OK;
	}
	else {
		return CSSMERR_CSP_VERIFY_FAILED;
	}
}
Пример #7
0
/*
 * Given a P12KeyBag, find a matching P12CertBag. Keys and certs
 * "match" if their localKeyIds match. Returns NULL if not found.
 */
P12CertBag *P12Coder::findCertForKey(
	P12KeyBag *keyBag)
{
	assert(keyBag != NULL);
	CSSM_DATA &keyKeyId = keyBag->localKeyIdCssm();
	
	for(unsigned dex=0; dex<numCerts(); dex++) {
		P12CertBag *certBag = mCerts[dex];
		CSSM_DATA &certKeyId = certBag->localKeyIdCssm();
		if(nssCompareCssmData(&keyKeyId, &certKeyId)) {
			p12DecodeLog("findCertForKey SUCCESS");
			return certBag;
		}
	}
	p12DecodeLog("findCertForKey FAILURE");
	return NULL;
}
/*
 * SafeBag via SEC_ASN1_DYNAMIC
 */
static const SecAsn1Template * NSS_P12_SafeBagChooser(
	void *arg, 			// --> NSS_P12_SafeBag
	Boolean enc,
	const char *buf,	// on decode, tag byte
	void *dest)			// --> NSS_P12_SafeBag.bagValue
{
	NSS_P12_SafeBag *bag = (NSS_P12_SafeBag *)arg;
	const SecAsn1Template *templ = NULL;
	NSS_P12_SB_Type type = BT_None;
	CSSM_OID *oid = &bag->bagId;
	
	if(nssCompareCssmData(oid, &CSSMOID_PKCS12_keyBag)) {
		templ = NSS_P12_PtrToKeyBagTemplate;
		type = BT_KeyBag;
	}
	else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_shroudedKeyBag)) {
		templ = NSS_P12_PtrToShroudedKeyBagTemplate;
		type = BT_ShroudedKeyBag;
	}
	else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_certBag)) {
		templ = NSS_P12_PtrToCertBagTemplate;
		type = BT_CertBag;
	}
	else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_crlBag)) {
		templ = NSS_P12_PtrToCrlBagTemplate;
		type = BT_CrlBag;
	}
	else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_secretBag)) {
		templ = NSS_P12_PtrToSecretBagTemplate;
		type = BT_SecretBag;
	}
	else if(nssCompareCssmData(oid, &CSSMOID_PKCS12_safeContentsBag)) {
		templ = NSS_P12_PtrToSafeContentsBagTemplate;
		type = BT_SafeContentsBag;
	}
	/* add more here when we implement them */
	else {
		templ = kSecAsn1PointerToAnyTemplate;
	}
	if(!enc) {
		bag->type = type;
	}
	return templ;
}
Пример #9
0
/*
 * Given an ECDSA key in CSSM format, extract the SSL_ECDSA_NamedCurve
 * from its algorithm parameters.
 */
OSStatus sslEcdsaPeerCurve(
	CSSM_KEY_PTR pubKey,
	SSL_ECDSA_NamedCurve *namedCurve)
{
	SecAsn1CoderRef coder = NULL;
	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo;
	CSSM_X509_ALGORITHM_IDENTIFIER *algId = &subjPubKeyInfo.algorithm;
	CSSM_OID curveOid;
	OSStatus ortn;

	CSSM_KEYHEADER *hdr = &pubKey->KeyHeader;
	if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) {
	   sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n");
	   return errSSLProtocol;
	}
	if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
		/* No can do - this must be raw format, it came from the CL */
	   sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n");
	   return errSSLProtocol;
	}
	if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) {
	   sslErrorLog("sslEcdsaPeerCurve: bad peer key format\n");
	   return errSSLProtocol;
	}

	/* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
	ortn = SecAsn1CoderCreate(&coder);
	if(ortn) {
		return errSSLInternal;
	}
	/* subsequent errors to errOut: */

	memset(&subjPubKeyInfo, 0, sizeof(subjPubKeyInfo));
	ortn = SecAsn1DecodeData(coder, &pubKey->KeyData, kSecAsn1SubjectPublicKeyInfoTemplate,
		&subjPubKeyInfo);
	if(ortn) {
		printf("sslEcdsaPeerCurve: error decoding public key\n");
		goto errOut;
	}

	if(!nssCompareCssmData(&algId->algorithm, &CSSMOID_ecPublicKey)) {
		printf("sslEcdsaPeerCurve: unexpected algorithm ID in public key\n");
		ortn = errSSLProtocol;
		goto errOut;
	}
	if((algId->parameters.Data[0] != BER_TAG_OID) ||
	   (algId->parameters.Length < 2)) {
		printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n");
		ortn = errSSLProtocol;
		goto errOut;
	}

	/*
	 * The curve OID is DER-encoded since the parameters are ASN_ANY.
	 * Quickie decode for further processing...
	 */
	curveOid.Data = algId->parameters.Data + 2;
	curveOid.Length = algId->parameters.Length - 2;

	/* algId->parameters is the curve OID */
	if(nssCompareCssmData(&curveOid, &CSSMOID_secp256r1)) {
		*namedCurve = SSL_Curve_secp256r1;
	}
	else if(nssCompareCssmData(&curveOid, &CSSMOID_secp384r1)) {
		*namedCurve = SSL_Curve_secp384r1;
	}
	else if(nssCompareCssmData(&curveOid, &CSSMOID_secp521r1)) {
		*namedCurve = SSL_Curve_secp521r1;
	}
	/* Others? Later. That's all we support for now. */
	else {
		printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n");
		ortn = errSSLProtocol;
	}

errOut:
	SecAsn1CoderRelease(coder);
	return ortn;
}