/* * Copyright (c) 2003-2004,2011-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@ */ /* * SecPkcs12.cpp */ #include "SecPkcs12.h" #include "pkcs12Coder.h" #include "pkcs12BagAttrs.h" #include "pkcs12SafeBag.h" #include "pkcs12Utils.h" #include #include /* * API function call wrappers, impermeable to C++ exceptions */ #define BEGIN_P12API \ try { #define END_P12API \ } \ catch (const MacOSError &err) { return err.osStatus(); } \ catch (const CommonError &err) { return SecKeychainErrFromOSStatus(err.osStatus()); } \ catch (const std::bad_alloc &) { return errSecAllocate; } \ catch (...) { return errSecInternalComponent; } \ return errSecSuccess; /* catch incoming NULL parameters */ static inline void required( const void *param) { if(param == NULL) { MacOSError::throwMe(errSecParam); } } /* * Standard means of casting a SecPkcs12CoderRef to a P12Coder * */ static inline P12Coder *P12CoderCast( SecPkcs12CoderRef coder) { required(coder); return reinterpret_cast(coder); } /* * Standard means of casting a SecPkcs12AttrsRef to a P12BagAttrs * * This one uses the P12BagAttrsStandAlone version, not tied to * a specific P12Coder (actually, to a P12Coder's SecNssCoder). */ static inline P12BagAttrsStandAlone *P12AttrsCast( SecPkcs12AttrsRef attrs) { if(attrs == NULL) { MacOSError::throwMe(errSecParam); } return reinterpret_cast(attrs); } /* optional flavor used in SecPkcs12Add*() */ static inline P12BagAttrs *P12AttrsCastOpt( SecPkcs12AttrsRef attrs) { return reinterpret_cast(attrs); } #pragma mark --- SecPkcs12CoderRef create/destroy --- /* * Basic SecPkcs12CoderRef create/destroy. */ OSStatus SecPkcs12CoderCreate( SecPkcs12CoderRef *coder) // RETURNED { BEGIN_P12API required(coder); P12Coder *p12coder = new P12Coder; *coder = p12coder; END_P12API } /* * Destroy object created in SecPkcs12CoderCreate. * This will go away if we make this object a CoreFoundation type. */ OSStatus SecPkcs12CoderRelease( SecPkcs12CoderRef coder) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); delete p12coder; END_P12API } OSStatus SecPkcs12SetMACPassphrase( SecPkcs12CoderRef coder, CFStringRef passphrase) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(passphrase); p12coder->setMacPassPhrase(passphrase); END_P12API } OSStatus SecPkcs12SetMACPassKey( SecPkcs12CoderRef coder, const CSSM_KEY *passKey) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(passKey); p12coder->setMacPassKey(passKey); END_P12API } /* * Specify separate passphrase for encrypt/decrypt. */ OSStatus SecPkcs12SetCryptPassphrase( SecPkcs12CoderRef coder, CFStringRef passphrase) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(passphrase); p12coder->setEncrPassPhrase(passphrase); END_P12API } OSStatus SecPkcs12SetCryptPassKey( SecPkcs12CoderRef coder, const CSSM_KEY *passKey) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(passKey); p12coder->setEncrPassKey(passKey); END_P12API } /* * Target location of decoded keys and certs. */ OSStatus SecPkcs12SetKeychain( SecPkcs12CoderRef coder, SecKeychainRef keychain) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(keychain); p12coder->setKeychain(keychain); END_P12API } /* * Required iff SecPkcs12SetKeychain() not called. */ OSStatus SecPkcs12SetCspHandle( SecPkcs12CoderRef coder, CSSM_CSP_HANDLE cspHandle) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->setCsp(cspHandle); END_P12API } OSStatus SecPkcs12SetImportToKeychain( SecPkcs12CoderRef coder, SecPkcs12ImportFlags flags) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->importFlags(flags); END_P12API } OSStatus SecPkcs12GetImportToKeychain( SecPkcs12CoderRef coder, SecPkcs12ImportFlags *flags) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(flags); *flags = p12coder->importFlags(); END_P12API } OSStatus SecPkcs12ExportKeychainItems( SecPkcs12CoderRef coder, CFArrayRef items) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(items); p12coder->exportKeychainItems(items); END_P12API } OSStatus SecPkcs12SetAccess( SecPkcs12CoderRef coder, SecAccessRef access) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->setAccess(access); END_P12API } OSStatus SecPkcs12SetKeyUsage( SecPkcs12CoderRef coder, CSSM_KEYUSE keyUsage) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->setKeyUsage(keyUsage); END_P12API } OSStatus SecPkcs12SetKeyAttrs( SecPkcs12CoderRef coder, CSSM_KEYATTR_FLAGS keyAttrs) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->setKeyAttrs(keyAttrs); END_P12API } #pragma mark --- Decoder Functions --- /* * Parse and decode. */ OSStatus SecPkcs12Decode( SecPkcs12CoderRef coder, CFDataRef pfx) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(pfx); try { p12coder->decode(pfx); } catch(...) { /* abort - clean up - delete stored keys */ p12coder->deleteDecodedItems(); throw; } END_P12API } /* * Subsequent to decoding, obtain the components. * These functions can also be used as "getter" functions while encoding. * * Certificates: */ OSStatus SecPkcs12CertificateCount( SecPkcs12CoderRef coder, CFIndex *numCerts) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(numCerts); *numCerts = p12coder->numCerts(); END_P12API } OSStatus SecPkcs12CopyCertificate( SecPkcs12CoderRef coder, CFIndex certNum, SecCertificateRef *secCert, // RETURNED CFStringRef *friendlyName, // RETURNED CFDataRef *localKeyId, // RETURNED SecPkcs12AttrsRef *attrs) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(secCert); /* others are optional - if NULL, we don't return that param */ P12CertBag *bag = p12coder->getCert((unsigned)certNum); *secCert = bag->getSecCert(); /* now the optional attrs */ P12BagAttrs *p12Attrs = NULL; bag->copyAllAttrs(friendlyName, localKeyId, attrs ? &p12Attrs : NULL); if(p12Attrs) { *attrs = p12Attrs; } END_P12API } /* * CRLs. The might change if a SecCrl type is defined elsewhere. * We'll typedef it here to preserve the semantics of this function. */ OSStatus SecPkcs12CrlCount( SecPkcs12CoderRef coder, CFIndex *numCrls) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(numCrls); *numCrls = p12coder->numCrls(); END_P12API } OSStatus SecPkcs12CopyCrl( SecPkcs12CoderRef coder, CFIndex crlNum, SecCrlRef *crl, // RETURNED CFStringRef *friendlyName, // RETURNED CFDataRef *localKeyId, // RETURNED SecPkcs12AttrsRef *attrs) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(crl); /* others are optional - if NULL, we don't return that param */ P12CrlBag *bag = p12coder->getCrl((unsigned)crlNum); *crl = p12CssmDataToCf(bag->crlData()); /* now the optional attrs */ P12BagAttrs *p12Attrs = NULL; bag->copyAllAttrs(friendlyName, localKeyId, attrs ? &p12Attrs : NULL); if(p12Attrs) { *attrs = p12Attrs; } END_P12API } /* * Private keys. */ OSStatus SecPkcs12PrivateKeyCount( SecPkcs12CoderRef coder, CFIndex *numKeys) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(numKeys); *numKeys = p12coder->numKeys(); END_P12API } OSStatus SecPkcs12CopyPrivateKey( SecPkcs12CoderRef coder, CFIndex keyNum, SecKeyRef *privateKey, // RETURNED CFStringRef *friendlyName, // RETURNED CFDataRef *localKeyId, // RETURNED SecPkcs12AttrsRef *attrs) // RETURNED { BEGIN_P12API /*P12Coder *p12coder = P12CoderCast(coder); */ return errSecUnimplemented; END_P12API } OSStatus SecPkcs12GetCssmPrivateKey( SecPkcs12CoderRef coder, CFIndex keyNum, CSSM_KEY_PTR *privateKey, // RETURNED CFStringRef *friendlyName, // RETURNED CFDataRef *localKeyId, // RETURNED SecPkcs12AttrsRef *attrs) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(privateKey); /* others are optional - if NULL, we don't return that param */ P12KeyBag *bag = p12coder->getKey((unsigned)keyNum); *privateKey = bag->key(); /* now the optional attrs */ P12BagAttrs *p12Attrs = NULL; bag->copyAllAttrs(friendlyName, localKeyId, attrs ? &p12Attrs : NULL); if(p12Attrs) { *attrs = p12Attrs; } END_P12API } /* * Catch-all for other components not currently understood * or supported by this library. An "opaque blob" component * is identified by an OID and is obtained as an opaque data * blob. */ OSStatus SecPkcs12OpaqueBlobCount( SecPkcs12CoderRef coder, CFIndex *numBlobs) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(numBlobs); *numBlobs = p12coder->numOpaqueBlobs(); END_P12API } OSStatus SecPkcs12CopyOpaqueBlob( SecPkcs12CoderRef coder, CFIndex blobNum, CFDataRef *blobOid, // RETURNED CFDataRef *opaqueBlob, // RETURNED CFStringRef *friendlyName, // RETURNED CFDataRef *localKeyId, // RETURNED SecPkcs12AttrsRef *attrs) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(blobOid); required(opaqueBlob); /* others are optional - if NULL, we don't return that param */ P12OpaqueBag *bag = p12coder->getOpaque((unsigned)blobNum); *opaqueBlob = p12CssmDataToCf(bag->blob()); *blobOid = p12CssmDataToCf(bag->oid()); /* now the optional attrs */ P12BagAttrs *p12Attrs = NULL; bag->copyAllAttrs(friendlyName, localKeyId, attrs ? &p12Attrs : NULL); if(p12Attrs) { *attrs = p12Attrs; } END_P12API } #pragma mark --- Encoder Functions --- /* * This the final step to create an encoded PKCS12 PFX blob, * after calling some number of SecPkcs12Set* functions below. * The result is a DER_encoded PFX in PKCS12 lingo. */ OSStatus SecPkcs12Encode( SecPkcs12CoderRef coder, CFDataRef *pfx) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(pfx); p12coder->encode(pfx); END_P12API } /* * Add individual components. "Getter" functions are available * as described above (under "Functions used for decoding"). */ OSStatus SecPkcs12AddCertificate( SecPkcs12CoderRef coder, SecCertificateRef cert, CFStringRef friendlyName, // optional CFDataRef localKeyId, // optional SecPkcs12AttrsRef attrs) // optional { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(cert); CSSM_DATA certData; OSStatus ortn = SecCertificateGetData(cert, &certData); if(ortn) { return ortn; } CSSM_CERT_TYPE certType; ortn = SecCertificateGetType(cert, &certType); if(ortn) { return ortn; } NSS_P12_CertBagType type; switch(certType) { case CSSM_CERT_X_509v1: case CSSM_CERT_X_509v2: case CSSM_CERT_X_509v3: type = CT_X509; break; case CSSM_CERT_SDSIv1: type = CT_SDSI; break; default: type = CT_Unknown; break; } P12CertBag *bag = new P12CertBag(type, certData, friendlyName, localKeyId, P12AttrsCastOpt(attrs), p12coder->coder()); p12coder->addCert(bag); END_P12API } OSStatus SecPkcs12AddCrl( SecPkcs12CoderRef coder, SecCrlRef crl, CFStringRef friendlyName, // optional CFDataRef localKeyId, // optional SecPkcs12AttrsRef attrs) // optional { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(crl); P12CrlBag *bag = new P12CrlBag(CRT_X509, crl, friendlyName, localKeyId, P12AttrsCastOpt(attrs), p12coder->coder()); p12coder->addCrl(bag); END_P12API } OSStatus SecPkcs12AddPrivateKey( SecPkcs12CoderRef coder, SecKeyRef privateKey, CFStringRef friendlyName, // optional CFDataRef localKeyId, // optional SecPkcs12AttrsRef attrs) // optional { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(privateKey); const CSSM_KEY *cssmKey; OSStatus ortn = SecKeyGetCSSMKey(privateKey, &cssmKey); if(ortn) { return ortn; } P12KeyBag *bag = new P12KeyBag(cssmKey, p12coder->cspHand(), friendlyName, localKeyId, P12AttrsCastOpt(attrs), p12coder->coder()); p12coder->addKey(bag); END_P12API } #if 0 /* Unused */ OSStatus SecPkcs12AddCssmPrivateKey( SecPkcs12CoderRef coder, CSSM_KEY_PTR cssmKey, CFStringRef friendlyName, // optional CFDataRef localKeyId, // optional SecPkcs12AttrsRef attrs) // optional { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(cssmKey); P12KeyBag *bag = new P12KeyBag(cssmKey, p12coder->cspHand(), friendlyName, localKeyId, P12AttrsCastOpt(attrs), p12coder->coder()); p12coder->addKey(bag); END_P12API } #endif OSStatus SecPkcs12AddOpaqueBlob( SecPkcs12CoderRef coder, CFDataRef blobOid, CFDataRef opaqueBlob, CFStringRef friendlyName, // optional CFDataRef localKeyId, // optional SecPkcs12AttrsRef attrs) // optional { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(blobOid); required(opaqueBlob); P12OpaqueBag *bag = new P12OpaqueBag(blobOid, opaqueBlob, friendlyName, localKeyId, P12AttrsCastOpt(attrs), p12coder->coder()); p12coder->addOpaque(bag); END_P12API } #pragma mark --- Optional Functions --- /*** *** SecPkcs12AttrsRef manipulation. Optional and in fact expected to *** be rarely used, if ever. ***/ /* * Create/destroy. */ OSStatus SecPkcs12AttrsCreate( SecPkcs12AttrsRef *attrs) // RETURNED { BEGIN_P12API required(attrs); P12BagAttrsStandAlone *bagAttrs = new P12BagAttrsStandAlone; *attrs = (SecPkcs12AttrsRef)bagAttrs; END_P12API } OSStatus SecPkcs12AttrsRelease( SecPkcs12AttrsRef attrs) { BEGIN_P12API P12BagAttrsStandAlone *bagAttrs = P12AttrsCast(attrs); delete bagAttrs; END_P12API } /* * Add an OID/value set to an existing SecPkcs12AttrsRef. * Values are a CFArray containing an arbitrary number of * CFDataRefs. */ OSStatus SecPkcs12AttrsAddAttr( SecPkcs12AttrsRef attrs, CFDataRef attrOid, CFArrayRef attrValues) { BEGIN_P12API P12BagAttrsStandAlone *bagAttrs = P12AttrsCast(attrs); bagAttrs->addAttr(attrOid, attrValues); END_P12API } OSStatus SecPkcs12AttrCount( SecPkcs12AttrsRef attrs, CFIndex *numAttrs) // RETURNED { BEGIN_P12API P12BagAttrsStandAlone *bagAttrs = P12AttrsCast(attrs); required(numAttrs); *numAttrs = bagAttrs->numAttrs(); END_P12API } /* * Obtain n'th oid/value set from an existing SecPkcs12AttrsRef. */ OSStatus SecPkcs12AttrsGetAttr( SecPkcs12AttrsRef attrs, CFIndex attrNum, CFDataRef *attrOid, // RETURNED CFArrayRef *attrValues) // RETURNED { BEGIN_P12API P12BagAttrsStandAlone *bagAttrs = P12AttrsCast(attrs); required(attrOid); required(attrValues); bagAttrs->getAttr((unsigned)attrNum, attrOid, attrValues); END_P12API } OSStatus SecPkcs12SetIntegrityMode( SecPkcs12CoderRef coder, SecPkcs12Mode mode) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->integrityMode(mode); END_P12API } OSStatus SecPkcs12GetIntegrityMode( SecPkcs12CoderRef coder, SecPkcs12Mode *mode) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(mode); *mode = p12coder->integrityMode(); END_P12API } OSStatus SecPkcs12SetPrivacyMode( SecPkcs12CoderRef coder, SecPkcs12Mode mode) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->privacyMode(mode); END_P12API } OSStatus SecPkcs12GetPrivacyMode( SecPkcs12CoderRef coder, SecPkcs12Mode *mode) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(mode); *mode = p12coder->privacyMode(); END_P12API } /*** *** Encryption algorithms ***/ OSStatus SecPkcs12SetKeyEncryptionAlg( SecPkcs12CoderRef coder, CFDataRef encryptionAlg) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(encryptionAlg); p12coder->strongEncrAlg(encryptionAlg); END_P12API } OSStatus SecPkcs12SetCertCrlEncryptionAlg( SecPkcs12CoderRef coder, CFDataRef encryptionAlg) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(encryptionAlg); p12coder->weakEncrAlg(encryptionAlg); END_P12API } OSStatus SecPkcs12SetKeyEncryptionIterCount( SecPkcs12CoderRef coder, unsigned iterCount) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->strongEncrIterCount(iterCount); END_P12API } OSStatus SecPkcs12SetCertCrlEncryptionIterCount( SecPkcs12CoderRef coder, unsigned iterCount) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->weakEncrIterCount(iterCount); END_P12API } OSStatus SecPkcs12SetMacIterCount( SecPkcs12CoderRef coder, unsigned iterCount) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->macEncrIterCount(iterCount); END_P12API } OSStatus SecPkcs12CopyKeyEncryptionAlg( SecPkcs12CoderRef coder, CFDataRef *encryptionAlg) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(encryptionAlg); *encryptionAlg = p12coder->strongEncrAlg(); END_P12API } OSStatus SecPkcs12CopyCertCrlEncryptionAlg( SecPkcs12CoderRef coder, CFDataRef *encryptionAlg) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(encryptionAlg); *encryptionAlg = p12coder->weakEncrAlg(); END_P12API } OSStatus SecPkcs12CopyKeyEncryptionIterCount( SecPkcs12CoderRef coder, unsigned *iterCount) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(iterCount); *iterCount = p12coder->strongEncrIterCount(); END_P12API } OSStatus SecPkcs12CopyCertCrlEncryptionIterCount( SecPkcs12CoderRef coder, unsigned *iterCount) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(iterCount); *iterCount = p12coder->weakEncrIterCount(); END_P12API } OSStatus SecPkcs12CopyMacIterCount( SecPkcs12CoderRef coder, unsigned *iterCount) // RETURNED { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); required(iterCount); *iterCount = p12coder->macEncrIterCount(); END_P12API } OSStatus SecPkcs12LimitPrivateKeyImport( SecPkcs12CoderRef coder, bool foundOneKey) { BEGIN_P12API P12Coder *p12coder = P12CoderCast(coder); p12coder->limitPrivKeyImport(foundOneKey); END_P12API }