pkcs12Keychain.cpp [plain text]
#include "pkcs12Coder.h"
#include "pkcs12Templates.h"
#include "pkcs12Utils.h"
#include "pkcs12Debug.h"
#include "pkcs12Crypto.h"
#include <Security/cssmerr.h>
#include <security_cdsa_utils/cuDbUtils.h> // cuAddCrlToDb()
#include <security_asn1/nssUtils.h>
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include <security_cdsa_utilities/KeySchema.h>
#include <security_keychain/SecImportExportCrypto.h>
void P12Coder::storeDecodeResults()
{
assert(mKeychain != NULL);
assert(mDlDbHand.DLHandle != 0);
if(mImportFlags & kSecImportKeys) {
setPrivateKeyHashes();
}
if(mImportFlags & kSecImportCertificates) {
for(unsigned dex=0; dex<numCerts(); dex++) {
P12CertBag *certBag = mCerts[dex];
SecCertificateRef secCert = certBag->getSecCert();
OSStatus ortn = SecCertificateAddToKeychain(secCert, mKeychain);
CFRelease(secCert);
switch(ortn) {
case noErr: p12DecodeLog("cert added to keychain");
break;
case errSecDuplicateItem: p12DecodeLog("skipping dup cert");
break;
default:
p12ErrorLog("SecCertificateAddToKeychain failure\n");
MacOSError::throwMe(ortn);
}
}
}
if(mImportFlags & kSecImportCRLs) {
for(unsigned dex=0; dex<numCrls(); dex++) {
P12CrlBag *crlBag = mCrls[dex];
CSSM_RETURN crtn = cuAddCrlToDb(mDlDbHand,
clHand(),
&crlBag->crlData(),
NULL); switch(crtn) {
case CSSM_OK: p12DecodeLog("CRL added to keychain");
break;
case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA: p12DecodeLog("skipping dup CRL");
break;
default:
p12LogCssmError("Error adding CRL to keychain", crtn);
CssmError::throwMe(crtn);
}
}
}
if(mImportFlags & kSecImportKeys) {
notifyKeyImport();
}
}
void P12Coder::setPrivateKeyHashes()
{
CSSM_KEY_PTR newKey;
for(unsigned dex=0; dex<numKeys(); dex++) {
P12KeyBag *keyBag = mKeys[dex];
CSSM_DATA newLabel = {0, NULL};
CFStringRef friendlyName = keyBag->friendlyName();
newKey = NULL;
CSSM_RETURN crtn = p12SetPubKeyHash(mCspHand,
mDlDbHand,
keyBag->label(),
p12StringToUtf8(friendlyName, mCoder),
mCoder,
newLabel,
newKey);
if(friendlyName) {
CFRelease(friendlyName);
}
switch(crtn) {
case CSSM_OK:
keyBag->setLabel(newLabel);
p12DecodeLog("set pub key hash for private key");
break;
case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA:
p12DecodeLog("ignoring dup private key");
assert(newKey != NULL);
keyBag->setKey(newKey);
keyBag->dupKey(true);
keyBag->setLabel(newLabel);
break;
default:
p12ErrorLog("p12SetPubKeyHash failure\n");
CssmError::throwMe(crtn);
}
}
}
void P12Coder::notifyKeyImport()
{
if(mKeychain == NULL) {
return;
}
for(unsigned dex=0; dex<numKeys(); dex++) {
P12KeyBag *keyBag = mKeys[dex];
if(keyBag->dupKey()) {
continue;
}
CssmData &labelData = CssmData::overlay(keyBag->label());
OSStatus ortn = impExpKeyNotify(mKeychain, labelData, *keyBag->key());
if(ortn) {
p12ErrorLog("notifyKeyImport: impExpKeyNotify returned %ld\n", ortn);
MacOSError::throwMe(ortn);
}
}
}
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;
}
void P12Coder::exportKeychainItems(
CFArrayRef items)
{
assert(items != NULL);
CFIndex numItems = CFArrayGetCount(items);
for(CFIndex dex=0; dex<numItems; dex++) {
const void *item = CFArrayGetValueAtIndex(items, dex);
if(item == NULL) {
p12ErrorLog("exportKeychainItems: NULL item\n");
MacOSError::throwMe(paramErr);
}
CFTypeID itemType = CFGetTypeID(item);
if(itemType == SecCertificateGetTypeID()) {
addSecCert((SecCertificateRef)item);
}
else if(itemType == SecKeyGetTypeID()) {
addSecKey((SecKeyRef)item);
}
else {
p12ErrorLog("exportKeychainItems: unknown item\n");
MacOSError::throwMe(paramErr);
}
}
}
static OSStatus attrNameToInt(
const char *name,
UInt32 *attrInt)
{
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *attrList =
KeySchema::KeySchemaAttributeList;
unsigned numAttrs = KeySchema::KeySchemaAttributeCount;
for(unsigned dex=0; dex<numAttrs; dex++) {
const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *info = &attrList[dex];
if(!strcmp(name, info->AttributeName)) {
*attrInt = info->AttributeId;
return noErr;
}
}
return paramErr;
}
void P12Coder::addSecKey(
SecKeyRef keyRef)
{
UInt32 printNameTag;
OSStatus ortn = attrNameToInt(P12_KEY_ATTR_PRINT_NAME, &printNameTag);
if(ortn) {
p12ErrorLog("addSecKey: problem looking up key attr name\n");
MacOSError::throwMe(ortn);
}
UInt32 labelHashTag;
ortn = attrNameToInt(P12_KEY_ATTR_LABEL_AND_HASH, &labelHashTag);
if(ortn) {
p12ErrorLog("addSecKey: problem looking up key attr name\n");
MacOSError::throwMe(ortn);
}
UInt32 tags[2];
tags[0] = printNameTag;
tags[1] = labelHashTag;
SecKeychainAttributeInfo attrInfo;
attrInfo.count = 2;
attrInfo.tag = tags;
attrInfo.format = NULL;
SecKeychainAttributeList *attrList = NULL;
ortn = SecKeychainItemCopyAttributesAndData(
(SecKeychainItemRef)keyRef,
&attrInfo,
NULL, &attrList,
NULL, NULL);
if(ortn) {
p12ErrorLog("addSecKey: SecKeychainItemCopyAttributesAndData "
"error\n");
MacOSError::throwMe(ortn);
}
CFStringRef friendName = NULL;
CFDataRef localKeyId = NULL;
for(unsigned i=0; i<attrList->count; i++) {
SecKeychainAttribute *attr = &attrList->attr[i];
if(attr->tag == printNameTag) {
friendName = CFStringCreateWithBytes(NULL,
(UInt8 *)attr->data, attr->length,
kCFStringEncodingUTF8, false);
}
else if(attr->tag == labelHashTag) {
localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
}
else {
p12ErrorLog("addSecKey: unexpected attr tag\n");
MacOSError::throwMe(paramErr);
}
}
SecKeychainRef kcRef;
ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef);
if(ortn) {
p12ErrorLog("addSecKey: SecKeychainItemCopyKeychain returned %d\n", (int)ortn);
MacOSError::throwMe(ortn);
}
CSSM_CSP_HANDLE cspHand;
ortn = SecKeychainGetCSPHandle(kcRef, &cspHand);
if(ortn) {
p12ErrorLog("addSecKey: SecKeychainGetCSPHandle returned %d\n", (int)ortn);
MacOSError::throwMe(ortn);
}
CFRelease(kcRef);
const CSSM_KEY *cssmKey;
ortn = SecKeyGetCSSMKey(keyRef, &cssmKey);
if(ortn) {
p12ErrorLog("addSecKey: SecKeyGetCSSMKey returned %d\n", (int)ortn);
MacOSError::throwMe(ortn);
}
P12KeyBag *keyBag = new P12KeyBag(cssmKey,
cspHand,
friendName, localKeyId,
NULL, mCoder,
keyRef);
addKey(keyBag);
SecKeychainItemFreeAttributesAndData(attrList, NULL);
if(friendName) {
CFRelease(friendName);
}
if(localKeyId) {
CFRelease(localKeyId);
}
}
void P12Coder::addSecCert(
SecCertificateRef certRef)
{
SecKeychainAttributeInfo attrInfo;
attrInfo.count = 2;
UInt32 tags[2] = {kSecLabelItemAttr, kSecPublicKeyHashItemAttr};
attrInfo.tag = tags;
attrInfo.format = NULL;
SecKeychainAttributeList *attrList = NULL;
UInt32 certLen;
void *certData;
OSStatus ortn = SecKeychainItemCopyAttributesAndData(
(SecKeychainItemRef)certRef,
&attrInfo,
NULL, &attrList,
&certLen,
&certData);
if(ortn) {
p12ErrorLog("addSecCert: SecKeychainItemCopyAttributesAndData "
"error\n");
MacOSError::throwMe(ortn);
}
CFStringRef friendName = NULL;
CFDataRef localKeyId = NULL;
for(unsigned i=0; i<attrList->count; i++) {
SecKeychainAttribute *attr = &attrList->attr[i];
switch(attr->tag) {
case kSecPublicKeyHashItemAttr:
localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length);
break;
case kSecLabelItemAttr:
friendName = CFStringCreateWithBytes(NULL,
(UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8,
false);
break;
default:
p12ErrorLog("addSecCert: unexpected attr tag\n");
MacOSError::throwMe(paramErr);
}
}
CSSM_DATA cData = {certLen, (uint8 *)certData};
P12CertBag *certBag = new P12CertBag(CT_X509, cData, friendName,
localKeyId, NULL, mCoder);
addCert(certBag);
SecKeychainItemFreeAttributesAndData(attrList, certData);
if(friendName) {
CFRelease(friendName);
}
if(localKeyId) {
CFRelease(localKeyId);
}
}
void P12Coder::deleteDecodedItems()
{
if(!(mImportFlags & kSecImportKeys)) {
return;
}
if(mDlDbHand.DLHandle == 0) {
return;
}
unsigned nKeys = numKeys();
for(unsigned dex=0; dex<nKeys; dex++) {
P12KeyBag *keyBag = mKeys[dex];
p12DeleteKey(mDlDbHand, keyBag->label());
}
}