#include "pkcs12Coder.h"
#include "pkcs12Templates.h"
#include "pkcs12Utils.h"
#include "pkcs12Debug.h"
#include "pkcs12Crypto.h"
#include <security_cdsa_utilities/cssmerrors.h>
#include <security_asn1/nssUtils.h>
void P12Coder::decode(
CFDataRef cdpfx)
{
SecNssCoder localCdr;
NSS_P12_DecodedPFX pfx;
p12DecodeLog("decode");
memset(&pfx, 0, sizeof(pfx));
const CSSM_DATA rawBlob = {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) {
p12ErrorLog("bad top-level contentType\n");
P12_THROW_DECODE;
}
mIntegrityMode = kSecPkcs12ModePassword;
if(pfx.macData == NULL) {
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);
if(mKeychain != NULL) {
storeDecodeResults();
}
}
void P12Coder::encryptedDataDecrypt(
const NSS_P7_EncryptedData &edata,
SecNssCoder &localCdr,
NSS_P12_PBE_Params *pbep, CSSM_DATA &ptext) {
p12DecodeLog("encryptedDataDecrypt");
CSSM_ALGORITHMS keyAlg; CSSM_ALGORITHMS encrAlg; CSSM_ALGORITHMS pbeHashAlg; uint32 keySizeInBits;
uint32 blockSizeInBytes; CSSM_PADDING padding; CSSM_ENCRYPT_MODE mode; PKCS_Which pkcs;
bool found = pkcsOidToParams(&edata.contentInfo.encrAlg.algorithm,
keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
padding, mode, pkcs);
if(!found || (pkcs != PW_PKCS12)) {
p12ErrorLog("EncryptedData encrAlg not understood\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
uint32 iterCount;
if(!p12DataToInt(pbep->iterations, iterCount)) {
p12ErrorLog("encryptedDataDecrypt: badly formed iterCount\n");
P12_THROW_DECODE;
}
const CSSM_DATA *pwd = getEncrPassPhrase();
const CSSM_KEY *passKey = getEncrPassKey();
if((pwd == NULL) && (passKey == NULL)) {
p12ErrorLog("no passphrase set\n");
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE);
}
CSSM_RETURN crtn = p12Decrypt(mCspHand,
edata.contentInfo.encrContent,
keyAlg, encrAlg, pbeHashAlg,
keySizeInBits, blockSizeInBytes,
padding, mode,
iterCount, pbep->salt,
pwd,
passKey,
localCdr,
ptext);
if(crtn) {
CssmError::throwMe(crtn);
}
}
void P12Coder::algIdParse(
const CSSM_X509_ALGORITHM_IDENTIFIER &algId,
NSS_P12_PBE_Params *pbeParams, SecNssCoder &localCdr)
{
p12DecodeLog("algIdParse");
const CSSM_DATA ¶m = algId.parameters;
if(pbeParams == NULL) {
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 P12Coder::encryptedDataParse(
const NSS_P7_EncryptedData &edata,
SecNssCoder &localCdr,
NSS_P12_PBE_Params *pbep) {
p12DecodeLog("encryptedDataParse");
const NSS_P7_EncrContentInfo &ci = edata.contentInfo;
const CSSM_X509_ALGORITHM_IDENTIFIER &algId = ci.encrAlg;
algIdParse(algId, pbep, localCdr);
}
void P12Coder::shroudedKeyBagParse(
const NSS_P12_SafeBag &safeBag,
SecNssCoder &localCdr)
{
p12DecodeLog("Found shrouded key bag");
if(mPrivKeyImportState == PKIS_NoMore) {
CssmError::throwMe(errSecMultiplePrivKeys);
}
const NSS_P12_ShroudedKeyBag *keyBag = safeBag.bagValue.shroudedKeyBag;
const CSSM_X509_ALGORITHM_IDENTIFIER &algId = keyBag->algorithm;
NSS_P12_PBE_Params pbep;
algIdParse(algId, &pbep, localCdr);
CSSM_ALGORITHMS keyAlg; CSSM_ALGORITHMS encrAlg; CSSM_ALGORITHMS pbeHashAlg; uint32 keySizeInBits;
uint32 blockSizeInBytes; CSSM_PADDING padding; CSSM_ENCRYPT_MODE mode; PKCS_Which pkcs;
bool found = pkcsOidToParams(&algId.algorithm,
keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes,
padding, mode, pkcs);
if(!found || (pkcs != PW_PKCS12)) {
p12ErrorLog("ShroudedKeyBag encrAlg not understood\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
uint32 iterCount;
if(!p12DataToInt(pbep.iterations, iterCount)) {
p12ErrorLog("ShroudedKeyBag: badly formed iterCount\n");
P12_THROW_DECODE;
}
const CSSM_DATA *encrPhrase = getEncrPassPhrase();
const CSSM_KEY *passKey = getEncrPassKey();
if((encrPhrase == NULL) && (passKey == NULL)) {
p12ErrorLog("no passphrase set\n");
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE);
}
CSSM_KEY_PTR privKey = (CSSM_KEY_PTR)mCoder.malloc(sizeof(CSSM_KEY));
memset(privKey, 0, sizeof(CSSM_KEY));
CSSM_DATA labelData;
p12GenLabel(labelData, localCdr);
CSSM_RETURN crtn = p12UnwrapKey(mCspHand,
mDlDbHand.DLHandle ? &mDlDbHand : NULL,
mImportFlags & kSecImportKeys,
keyBag->encryptedData,
keyAlg, encrAlg, pbeHashAlg,
keySizeInBits, blockSizeInBytes,
padding, mode,
iterCount, pbep.salt,
encrPhrase,
passKey,
localCdr,
labelData,
mAccess,
mNoAcl,
mKeyUsage,
mKeyAttrs,
privKey);
if(crtn) {
p12ErrorLog("Error unwrapping private key\n");
CssmError::throwMe(crtn);
}
p12DecodeLog("unwrapped shrouded key bag");
P12KeyBag *p12bag = new P12KeyBag(privKey, mCspHand,
safeBag.bagAttrs, labelData, mCoder);
addKey(p12bag);
if(mPrivKeyImportState == PKIS_AllowOne) {
mPrivKeyImportState = PKIS_NoMore;
}
}
void P12Coder::keyBagParse(
const NSS_P12_SafeBag &safeBag,
SecNssCoder &localCdr)
{
if(mPrivKeyImportState == PKIS_NoMore) {
CssmError::throwMe(errSecMultiplePrivKeys);
}
p12DecodeLog("found keyBag");
NSS_P12_KeyBag *keyBag = safeBag.bagValue.keyBag;
P12OpaqueBag *p12Bag = new P12OpaqueBag(safeBag.bagId,
*keyBag,
safeBag.bagAttrs,
mCoder);
addOpaque(p12Bag);
}
void P12Coder::certBagParse(
const NSS_P12_SafeBag &safeBag,
SecNssCoder &localCdr)
{
p12DecodeLog("found certBag");
NSS_P12_CertBag *certBag = safeBag.bagValue.certBag;
switch(certBag->type) {
case CT_X509:
case CT_SDSI:
break;
default:
p12ErrorLog("certBagParse: unknown cert type\n");
P12_THROW_DECODE;
}
P12CertBag *p12Bag = new P12CertBag(certBag->type,
certBag->certValue,
safeBag.bagAttrs,
mCoder);
addCert(p12Bag);
}
void P12Coder::crlBagParse(
const NSS_P12_SafeBag &safeBag,
SecNssCoder &localCdr)
{
p12DecodeLog("found crlBag");
NSS_P12_CrlBag *crlBag = safeBag.bagValue.crlBag;
switch(crlBag->type) {
case CRT_X509:
break;
default:
p12ErrorLog("crlBagParse: unknown CRL type\n");
P12_THROW_DECODE;
}
P12CrlBag *p12Bag = new P12CrlBag(crlBag->type,
crlBag->crlValue,
safeBag.bagAttrs,
mCoder);
addCrl(p12Bag);
}
void P12Coder::secretBagParse(
const NSS_P12_SafeBag &safeBag,
SecNssCoder &localCdr)
{
p12DecodeLog("found secretBag");
NSS_P12_SecretBag *secretBag = safeBag.bagValue.secretBag;
P12OpaqueBag *p12Bag = new P12OpaqueBag(safeBag.bagId,
*secretBag,
safeBag.bagAttrs,
mCoder);
addOpaque(p12Bag);
}
void P12Coder::safeContentsBagParse(
const NSS_P12_SafeBag &safeBag,
SecNssCoder &localCdr)
{
p12DecodeLog("found SafeContents safe bag");
NSS_P12_SafeContentsBag *scBag = safeBag.bagValue.safeContentsBag;
P12OpaqueBag *p12Bag = new P12OpaqueBag(safeBag.bagId,
*scBag,
safeBag.bagAttrs,
mCoder);
addOpaque(p12Bag);
}
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);
if(bag->bagValue.keyBag == NULL) {
p12ErrorLog("safeContentsParse: Empty SafeBag\n");
P12_THROW_DECODE;
}
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 P12Coder::authSafeElementParse(
const NSS_P7_DecodedContentInfo *info,
SecNssCoder &localCdr)
{
p12DecodeLog("authSafeElementParse");
switch(info->type) {
case CT_Data:
safeContentsParse(*info->content.data, localCdr);
break;
case CT_EncryptedData:
{
NSS_P12_PBE_Params pbep;
encryptedDataParse(*info->content.encryptData, localCdr, &pbep);
CSSM_DATA ptext = {0, NULL};
encryptedDataDecrypt(*info->content.encryptData,
localCdr, &pbep, ptext);
safeContentsParse(ptext, localCdr);
break;
}
default:
p12ErrorLog("authSafeElementParse: unknown sage type (%u)\n",
(unsigned)info->type);
P12OpaqueBag *opaque = new P12OpaqueBag(
info->contentType, *info->content.data,
NULL, localCdr);
addOpaque(opaque);
break;
}
}
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 P12Coder::macParse(
const NSS_P12_MacData &macData,
SecNssCoder &localCdr)
{
p12DecodeLog("macParse");
algIdParse(macData.mac.digestAlgorithm, NULL, localCdr);
const CSSM_DATA &iter = macData.iterations;
if(iter.Length > 4) {
p12ErrorLog("malformed iteration length (%u)\n",
(unsigned)iter.Length);
P12_THROW_DECODE;
}
}