#include "pkcs12SafeBag.h"
#include "pkcs12Debug.h"
#include "pkcs12Utils.h"
#include <string.h>
#include <security_utilities/simulatecrash_assert.h>
#include <Security/Security.h>
#include <Security/SecKeyPriv.h>
#include <Security/SecAsn1Templates.h>
#include <security_asn1/nssUtils.h>
P12SafeBag::P12SafeBag(
NSS_Attribute **attrs, SecNssCoder &coder)
: mBagAttrs(coder),
mCoder(coder)
{
mFriendlyName.Data = mLocalKeyId.Data = NULL;
mFriendlyName.Length = mLocalKeyId.Length = 0;
unsigned numAttrs = nssArraySize((const void **)attrs);
for(unsigned dex=0; dex<numAttrs; dex++) {
NSS_Attribute *attr = attrs[dex];
unsigned numValues = nssArraySize((const void**)attr->attrValue);
if(nssCompareCssmData(&attr->attrType,
&CSSMOID_PKCS9_FriendlyName)) {
if(numValues != 1) {
p12ErrorLog("FriendlyName with %u values\n", numValues);
if(numValues == 0) {
P12_THROW_DECODE;
}
}
if(mCoder.decodeItem(*attr->attrValue[0],
kSecAsn1BMPStringTemplate, &mFriendlyName)) {
p12ErrorLog("***Error decoding FriendlyName string\n");
P12_THROW_DECODE;
}
}
else if(nssCompareCssmData(&attr->attrType,
&CSSMOID_PKCS9_LocalKeyId)) {
if(numValues != 1) {
p12ErrorLog("LocalKeyId with %u values\n", numValues);
if(numValues == 0) {
P12_THROW_DECODE;
}
}
if(mCoder.decodeItem(*attr->attrValue[0],
kSecAsn1OctetStringTemplate, &mLocalKeyId)) {
p12ErrorLog("***Error decoding LocalKeyId\n");
P12_THROW_DECODE;
}
}
else {
mBagAttrs.addAttr(*attr);
}
}
}
P12SafeBag::P12SafeBag(
CFStringRef fname,
CFDataRef keyId,
P12BagAttrs *otherAttrs, SecNssCoder &coder)
: mBagAttrs(otherAttrs, coder),
mCoder(coder)
{
friendlyName(fname);
localKeyId(keyId);
}
P12SafeBag::~P12SafeBag()
{
}
void P12SafeBag::friendlyName(
CFStringRef fname)
{
CFIndex len = 0;
if(fname != NULL) {
len = CFStringGetLength(fname);
}
if(len == 0) {
mFriendlyName.Data = NULL;
mFriendlyName.Length = 0;
return;
}
unsigned flen = (unsigned)(len * sizeof(UniChar));
mCoder.allocItem(mFriendlyName, flen);
unsigned char *cp = mFriendlyName.Data;
for(CFIndex dex=0; dex<len; dex++) {
UniChar uc = CFStringGetCharacterAtIndex(fname, dex);
*cp++ = uc >> 8;
*cp++ = uc & 0xff;
}
}
void P12SafeBag::localKeyId(
CFDataRef keyId)
{
CFIndex len = 0;
if(keyId != NULL) {
len = CFDataGetLength(keyId);
}
if(len == 0) {
mLocalKeyId.Data = NULL;
mLocalKeyId.Length = 0;
return;
}
mCoder.allocItem(mLocalKeyId, len);
const UInt8 *cp = CFDataGetBytePtr(keyId);
memmove(mLocalKeyId.Data, cp, len);
}
void P12SafeBag::copyAllAttrs(
CFStringRef *fName,
CFDataRef *keyId,
P12BagAttrs **bagAttrs)
{
if(fName) {
*fName = friendlyName();
}
if(keyId) {
*keyId = localKeyId();
}
if(bagAttrs) {
if(mBagAttrs.numAttrs()) {
P12BagAttrs *attrs = new P12BagAttrs(&mBagAttrs, mCoder);
*bagAttrs = attrs;
}
else {
*bagAttrs = NULL;
}
}
}
CFStringRef CF_RETURNS_RETAINED P12SafeBag::friendlyName()
{
if(mFriendlyName.Data == NULL) {
return NULL;
}
assert((mFriendlyName.Length & 1) == 0);
unsigned long strLen = mFriendlyName.Length / 2;
UniChar *uc = (UniChar *)malloc(strLen * sizeof(UniChar));
const uint8 *inp = mFriendlyName.Data;
UniChar *outp = uc;
while(inp < (mFriendlyName.Data + mFriendlyName.Length)) {
*outp = (((unsigned)inp[0]) << 8) | inp[1];
outp++;
inp += 2;
}
CFStringRef cstr = CFStringCreateWithCharacters(NULL, uc, strLen);
free(uc);
return cstr;
}
CFDataRef CF_RETURNS_RETAINED P12SafeBag::localKeyId()
{
if(mLocalKeyId.Data == NULL) {
return NULL;
}
return CFDataCreate(NULL, (const UInt8 *)mLocalKeyId.Data,
mLocalKeyId.Length);
}
NSS_Attribute **P12SafeBag::getAllAttrs()
{
unsigned numAttrs = mBagAttrs.numAttrs();
if(mFriendlyName.Data) {
numAttrs++;
}
if(mLocalKeyId.Data) {
numAttrs++;
}
NSS_Attribute **attrs =
(NSS_Attribute **)p12NssNullArray(numAttrs, mCoder);
unsigned outDex=0;
for(unsigned i=0; i<mBagAttrs.numAttrs(); i++) {
attrs[outDex++] = mBagAttrs.getAttr(i);
}
if(mFriendlyName.Data) {
CSSM_DATA berName = {0, NULL};
if(mCoder.encodeItem(&mFriendlyName, kSecAsn1BMPStringTemplate,
berName)) {
p12ErrorLog("***Error encoding FriendlyName string\n");
P12_THROW_ENCODE;
}
attrs[outDex++] = makeAttr(CSSMOID_PKCS9_FriendlyName,
berName);
}
if(mLocalKeyId.Data) {
CSSM_DATA berName = {0, NULL};
if(mCoder.encodeItem(&mLocalKeyId, kSecAsn1OctetStringTemplate,
berName)) {
p12ErrorLog("***Error encoding LocalKeyId string\n");
P12_THROW_ENCODE;
}
attrs[outDex++] = makeAttr(CSSMOID_PKCS9_LocalKeyId,
berName);
}
assert(outDex == numAttrs);
return attrs;
}
NSS_Attribute *P12SafeBag::makeAttr(
const CSSM_OID &attrId,
const CSSM_DATA &attrValue)
{
NSS_Attribute *attr = mCoder.mallocn<NSS_Attribute>();
mCoder.allocCopyItem(attrId, attr->attrType);
attr->attrValue = mCoder.mallocn<CSSM_DATA *>(2);
attr->attrValue[0] = mCoder.mallocn<CSSM_DATA>();
attr->attrValue[1] = NULL;
mCoder.allocCopyItem(attrValue, *attr->attrValue[0]);
return attr;
}
P12CertBag::P12CertBag(
NSS_P12_CertBagType certType, CSSM_DATA &certData,
NSS_Attribute **attrs, SecNssCoder &coder)
: P12SafeBag(attrs, coder),
mCertType(certType),
mCertRef(NULL)
{
coder.allocCopyItem(certData, mCertData);
}
P12CertBag::P12CertBag(
NSS_P12_CertBagType certType, CSSM_DATA &certData,
CFStringRef fname,
CFDataRef keyId,
P12BagAttrs *otherAttrs,
SecNssCoder &coder)
: P12SafeBag(fname, keyId, otherAttrs, coder),
mCertType(certType),
mCertRef(NULL)
{
coder.allocCopyItem(certData, mCertData);
}
P12CertBag::~P12CertBag()
{
if(mCertRef) {
CFRelease(mCertRef);
}
}
SecCertificateRef P12CertBag::getSecCert()
{
if(mCertRef) {
CFRetain(mCertRef);
return mCertRef;
}
CSSM_CERT_TYPE certType;
CSSM_CERT_ENCODING certEncoding;
switch(mCertType) {
case CT_X509:
certType = CSSM_CERT_X_509v3;
certEncoding = CSSM_CERT_ENCODING_DER;
break;
case CT_SDSI:
certType = CSSM_CERT_SDSIv1;
certEncoding = CSSM_CERT_ENCODING_UNKNOWN;
break;
default:
certType = CSSM_CERT_UNKNOWN;
certEncoding = CSSM_CERT_ENCODING_UNKNOWN;
break;
}
OSStatus ortn = SecCertificateCreateFromData(
&mCertData,
certType,
certEncoding,
&mCertRef);
if(ortn) {
MacOSError::throwMe(ortn);
}
if (mCertRef) {
CFRetain(mCertRef);
}
return mCertRef;
}
P12CrlBag::P12CrlBag(
NSS_P12_CrlBagType crlType, CSSM_DATA &crlData,
NSS_Attribute **attrs, SecNssCoder &coder)
: P12SafeBag(attrs, coder),
mCrlType(crlType)
{
coder.allocCopyItem(crlData, mCrlData);
}
P12CrlBag::P12CrlBag(
NSS_P12_CrlBagType crlType, CFDataRef crlData,
CFStringRef fname,
CFDataRef keyId,
P12BagAttrs *otherAttrs,
SecNssCoder &coder)
: P12SafeBag(fname, keyId, otherAttrs, coder),
mCrlType(crlType)
{
coder.allocCopyItem(CFDataGetBytePtr(crlData),
CFDataGetLength(crlData), mCrlData);
}
P12CrlBag::~P12CrlBag()
{
}
P12KeyBag::P12KeyBag(
CSSM_KEY_PTR key,
CSSM_CSP_HANDLE cspHand,
NSS_Attribute **attrs, CSSM_DATA &labelData,
SecNssCoder &coder)
: P12SafeBag(attrs, coder),
mKey(key),
mCspHand(cspHand),
mKeyRef(NULL),
mWeOwnKey(true),
mPrivKeyCreds(NULL),
mDupKey(false)
{
setLabel(labelData);
}
P12KeyBag::P12KeyBag(
const CSSM_KEY *key,
CSSM_CSP_HANDLE cspHand,
CFStringRef fname,
CFDataRef keyId,
P12BagAttrs *otherAttrs,
SecNssCoder &coder,
SecKeyRef keyRef )
: P12SafeBag(fname, keyId, otherAttrs, coder),
mKey((CSSM_KEY_PTR)key),
mCspHand(cspHand),
mKeyRef(keyRef),
mWeOwnKey(false), mPrivKeyCreds(NULL),
mDupKey(false)
{
if(mKeyRef) {
CFRetain(mKeyRef);
OSStatus ortn = SecKeyGetCredentials(mKeyRef,
CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED,
kSecCredentialTypeDefault,
&mPrivKeyCreds);
if(ortn) {
p12LogCssmError("SecKeyGetCredentials", ortn);
MacOSError::throwMe(ortn);
}
}
mLabel.Data = NULL;
mLabel.Length = 0;
}
P12KeyBag::~P12KeyBag()
{
freeKey();
}
void P12KeyBag::setLabel(
const CSSM_DATA &newLabel)
{
mCoder.allocCopyItem(newLabel, mLabel);
}
void P12KeyBag::setKey(
CSSM_KEY_PTR cssmKey)
{
freeKey();
mKey = cssmKey;
}
void P12KeyBag::freeKey()
{
if(mWeOwnKey) {
assert(mKey != NULL);
assert(mCspHand != 0);
CSSM_FreeKey(mCspHand, NULL, mKey, CSSM_FALSE);
}
mKey = NULL;
if(mKeyRef) {
CFRelease(mKeyRef);
mKeyRef = NULL;
}
}
P12OpaqueBag::P12OpaqueBag(
const CSSM_OID &oid,
const CSSM_DATA &blob,
NSS_Attribute **attrs, SecNssCoder &coder)
: P12SafeBag(attrs, coder)
{
coder.allocCopyItem(oid, mOid);
coder.allocCopyItem(blob, mBlob);
}
P12OpaqueBag::P12OpaqueBag(
CFDataRef oid,
CFDataRef blob,
CFStringRef fname,
CFDataRef keyId,
P12BagAttrs *otherAttrs,
SecNssCoder &coder)
: P12SafeBag(fname, keyId, otherAttrs, coder)
{
coder.allocCopyItem(CFDataGetBytePtr(oid),
CFDataGetLength(oid), mOid);
coder.allocCopyItem(CFDataGetBytePtr(blob),
CFDataGetLength(blob), mBlob);
}
P12OpaqueBag::~P12OpaqueBag()
{
}