]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_pkcs12 / lib / pkcs12SafeBag.cpp
diff --git a/Security/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp b/Security/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp
new file mode 100644 (file)
index 0000000..51de12d
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2003-2004,2011-2012,2014 Apple Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * pkcs12SafeBag.cpp : internal representation of various kinds
+ *                   of P12 SafeBags
+ */
+#include "pkcs12SafeBag.h"
+#include "pkcs12Debug.h"
+#include "pkcs12Utils.h"
+#include <string.h>
+#include <assert.h>
+#include <Security/Security.h>
+#include <Security/SecKeyPriv.h>
+#include <Security/SecAsn1Templates.h>
+#include <security_asn1/nssUtils.h>
+
+/*
+ * P12SafeBag, abstract superclass of all safe bags.
+ *
+ * Constructor for decoding. Attr may include friendlyName and localKeyId;
+ * It may also be empty or NULL.
+ */
+P12SafeBag::P12SafeBag(
+       NSS_Attribute           **attrs, // including friendlyName, etc.
+       SecNssCoder             &coder)
+       : mBagAttrs(coder),
+         mCoder(coder)
+{
+       mFriendlyName.Data = mLocalKeyId.Data = NULL;
+       mFriendlyName.Length = mLocalKeyId.Length = 0;
+       
+       /* parse attrs into friendlyName, localKeyId, and generic attrs */
+       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)) {
+                       /* 
+                        * BMP string (UniCode). Spec says only one legal value.
+                        */
+                       if(numValues != 1) {
+                               p12ErrorLog("FriendlyName with %u values\n", numValues);
+                               /* but let's keep going if we can */
+                               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)) {
+                       /* 
+                        * Octet string. Spec says only one legal value.
+                        */
+                       if(numValues != 1) {
+                               p12ErrorLog("LocalKeyId with %u values\n", numValues);
+                               /* but let's keep going if we can */
+                               if(numValues == 0) {
+                                       P12_THROW_DECODE;
+                               }
+                       }
+                       if(mCoder.decodeItem(*attr->attrValue[0],
+                                       kSecAsn1OctetStringTemplate, &mLocalKeyId)) {
+                               p12ErrorLog("***Error decoding LocalKeyId\n");
+                               P12_THROW_DECODE;
+                       }
+               }
+               else {
+                       /* others */
+                       mBagAttrs.addAttr(*attr);
+               }
+       }
+}
+
+/*
+ * Constructor for encoding. All arguments except for the coder 
+ * are optional.
+ */
+P12SafeBag::P12SafeBag(
+       CFStringRef                     fname,
+       CFDataRef                       keyId,
+       P12BagAttrs                     *otherAttrs,            // optional
+       SecNssCoder             &coder)
+       : mBagAttrs(otherAttrs, coder),
+         mCoder(coder)
+{
+       friendlyName(fname);
+       localKeyId(keyId);
+}
+
+P12SafeBag::~P12SafeBag()
+{
+       /* nothing if everything we allocd is via mCoder */
+}
+
+/* 
+ * Setters in CF terms, used when constructing prior
+ * to encoding.
+ */
+void P12SafeBag::friendlyName(
+       CFStringRef             fname)
+{
+       CFIndex len = 0;
+       
+       if(fname != NULL) {
+               len = CFStringGetLength(fname);
+       }
+       if(len == 0) {
+               mFriendlyName.Data = NULL;
+               mFriendlyName.Length = 0;
+               return;
+       }
+       
+       /* convert unicode to byte array */
+       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);
+}
+
+/* 
+ * Copy out all attrs in API form. All incoming ptrs
+ * are optional.
+ */
+void P12SafeBag::copyAllAttrs(
+       CFStringRef             *fName,
+       CFDataRef                       *keyId,
+       P12BagAttrs                     **bagAttrs)
+{
+       if(fName) {
+               *fName = friendlyName();
+       }
+       if(keyId) {
+               *keyId = localKeyId();
+       }
+       if(bagAttrs) {
+               if(mBagAttrs.numAttrs()) {
+                       /* make a copy of our bag attrs */
+                       P12BagAttrs *attrs = new P12BagAttrs(&mBagAttrs, mCoder);
+                       *bagAttrs = attrs;
+               }
+               else {
+                       *bagAttrs = NULL;
+               }
+       }
+}
+
+
+/* getters in CF terms - result is created and returned */
+CFStringRef P12SafeBag::friendlyName()
+{
+       if(mFriendlyName.Data == NULL) {
+               /* not present, no error */
+               return NULL;
+       }
+       /* shouldn't have stored this if it's an odd number of bytes */
+       assert((mFriendlyName.Length & 1) == 0);
+       
+       /* convert byte array to unicode */
+       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 P12SafeBag::localKeyId()
+{
+       if(mLocalKeyId.Data == NULL) {
+               /* not present, no error */
+               return NULL;
+       }
+       return CFDataCreate(NULL, (const UInt8 *)mLocalKeyId.Data,
+               mLocalKeyId.Length);
+}
+
+/* 
+ * Get all attrs, including friendlyName and localKeyId,
+ * in preparation for encoding.
+ */
+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;
+}
+
+/*
+ * Create an NSS_Attribute * for friendlyName or keyId
+ */
+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;
+}
+
+/*
+ * Individual bag types 
+ */
+/* decode */
+P12CertBag::P12CertBag(
+       NSS_P12_CertBagType     certType,       // CT_X509, CT_SDSI
+       CSSM_DATA                       &certData,
+       NSS_Attribute           **attrs,        // optional
+       SecNssCoder                     &coder)
+               : P12SafeBag(attrs, coder),
+                 mCertType(certType),
+                 mCertRef(NULL)
+{
+       coder.allocCopyItem(certData, mCertData);
+}
+
+/* encode */
+P12CertBag::P12CertBag(
+       NSS_P12_CertBagType     certType,       // CT_X509, CT_SDSI
+       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);
+       }
+       /* everything else we allocd is via mCoder */
+}
+
+/* convert to P12CertBag to SecCertificateRef */
+SecCertificateRef P12CertBag::getSecCert()
+{
+       if(mCertRef) {
+               CFRetain(mCertRef);             /* a ref count for the caller */
+               return mCertRef;
+       }
+       
+       /* lazy creation... */
+       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;
+                       /* it's base64 encoded - no value for that in this enum */
+                       certEncoding = CSSM_CERT_ENCODING_UNKNOWN;
+                       break;
+               default:
+                       /* shouldn't currently happen, but... */
+                       certType = CSSM_CERT_UNKNOWN;
+                       certEncoding = CSSM_CERT_ENCODING_UNKNOWN;
+                       break;
+       }
+       OSStatus ortn = SecCertificateCreateFromData(
+               &mCertData,
+               certType,
+               certEncoding,
+               &mCertRef);
+       if(ortn) {
+               MacOSError::throwMe(ortn);
+       }
+       
+       /* One ref count for us, one for the caller */
+       CFRetain(mCertRef);
+       return mCertRef;
+}
+
+P12CrlBag::P12CrlBag(
+       NSS_P12_CrlBagType      crlType,        // CRT_X509, only for now
+       CSSM_DATA                       &crlData,
+       NSS_Attribute           **attrs,        // optional
+       SecNssCoder                     &coder)
+               : P12SafeBag(attrs, coder), 
+                 mCrlType(crlType)
+{
+       coder.allocCopyItem(crlData, mCrlData);
+}
+
+P12CrlBag::P12CrlBag(
+       NSS_P12_CrlBagType      crlType,        // CRT_X509, only for now
+       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()
+{
+       /* nothing if everything we allocd is via mCoder */
+}
+
+/* 
+ * For decode - both shrouded and plain.
+ * On decode, we own the key and will do the CSSM_FreeKey in
+ * our destructor. Caller owns the actual CSSM_KEY memory. 
+ */
+P12KeyBag::P12KeyBag(
+       CSSM_KEY_PTR            key,    
+       CSSM_CSP_HANDLE         cspHand,
+       NSS_Attribute           **attrs,        // optional
+       CSSM_DATA                       &labelData,
+       SecNssCoder                     &coder)
+               : P12SafeBag(attrs, coder),
+                 mKey(key),
+                 mCspHand(cspHand),
+                 mKeyRef(NULL),
+                 mWeOwnKey(true),
+                 mPrivKeyCreds(NULL),
+                 mDupKey(false)
+{
+       setLabel(labelData);
+}
+
+/* for encode - app owns CSSM_KEY */
+P12KeyBag::P12KeyBag(
+       const CSSM_KEY          *key,   
+       CSSM_CSP_HANDLE         cspHand,
+       CFStringRef                     fname,
+       CFDataRef                       keyId,
+       P12BagAttrs                     *otherAttrs,
+       SecNssCoder                     &coder,
+       SecKeyRef                       keyRef /* = NULL */)
+
+               : P12SafeBag(fname, keyId, otherAttrs, coder),
+                 mKey((CSSM_KEY_PTR)key),
+                 mCspHand(cspHand),
+                 mKeyRef(keyRef),
+                 mWeOwnKey(false),             // app giveth, app taketh away
+                 mPrivKeyCreds(NULL),
+                 mDupKey(false)
+{
+       if(mKeyRef) {
+               CFRetain(mKeyRef);
+               /* 
+                * Get creds associated with this key 
+                */
+               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);
+}
+
+/* reusable key setter */
+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;
+       }
+}
+
+/*
+ * Others we don't implement 
+ */
+P12OpaqueBag::P12OpaqueBag(
+       const CSSM_OID          &oid,
+       const CSSM_DATA         &blob,
+       NSS_Attribute           **attrs,        // optional
+       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()
+{
+       /* nothing if everything we allocd is via mCoder */
+}
+