SecExternalRep.cpp [plain text]
#include "SecExternalRep.h"
#include "SecImportExportPem.h"
#include "SecImportExportAgg.h"
#include "SecImportExportUtils.h"
#include "SecImportExportPkcs8.h"
#include "SecImportExportCrypto.h"
#include "SecImportExportOpenSSH.h"
#include <security_utilities/errors.h>
#include <Security/SecBase.h>
#include <Security/SecKeyPriv.h>
#include <Security/SecCertificate.h>
#include <Security/cssmapi.h>
using namespace Security;
using namespace KeychainCore;
#pragma mark --- SecExportRep Subclasses seen only by SecExportRep::vend() ---
namespace SecExport {
class Key : public SecExportRep
{
friend class SecExportRep;
protected:
Key(
CFTypeRef kcItemRef);
~Key();
OSStatus exportRep(
SecExternalFormat format,
SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, CFMutableDataRef outData, const char **pemHeader);
private:
CSSM_ALGORITHMS mKeyAlg;
const CSSM_KEY *mCssmKey;
};
class Cert : public SecExportRep
{
friend class SecExportRep;
protected:
Cert(
CFTypeRef kcItemRef);
~Cert();
OSStatus exportRep(
SecExternalFormat format,
SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, CFMutableDataRef outData, const char **pemHeader); };
}
#pragma mark --- SecExportRep: Representation of an internal object on export ---
SecExportRep::SecExportRep(
CFTypeRef kcItemRef) :
mKcItem((SecKeychainItemRef)kcItemRef),
mPemParamLines(NULL)
{
CFRetain(mKcItem);
}
SecExportRep::~SecExportRep()
{
if(mKcItem) {
CFRelease(mKcItem);
}
if(mPemParamLines) {
CFRelease(mPemParamLines);
}
}
SecExportRep::SecExportRep() {
MacOSError::throwMe(errSecInvalidItemRef);
}
OSStatus SecExportRep::exportRep(
SecExternalFormat format,
SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, CFMutableDataRef outData, const char **pemHeader) {
MacOSError::throwMe(errSecInvalidItemRef);
}
SecExportRep *SecExportRep::vend(
CFTypeRef kcItemRef)
{
CFTypeID itemType = CFGetTypeID(kcItemRef);
if(itemType == SecCertificateGetTypeID()) {
return new SecExport::Cert(kcItemRef);
}
else if(itemType == SecKeyGetTypeID()) {
return new SecExport::Key(kcItemRef);
}
else {
MacOSError::throwMe(errSecInvalidItemRef);
}
}
#pragma mark --- Key External rep ---
SecExport::Key::Key(
CFTypeRef kcItemRef) :
SecExportRep(kcItemRef)
{
OSStatus ortn;
ortn = SecKeyGetCSSMKey((SecKeyRef)kcItemRef, &mCssmKey);
if(ortn) {
SecImpExpDbg("SecKeyGetCSSMKey failure in SecExportRep::Key()");
MacOSError::throwMe(ortn);
}
switch(mCssmKey->KeyHeader.KeyClass) {
case CSSM_KEYCLASS_PUBLIC_KEY:
mExternType = kSecItemTypePublicKey;
SecImpExpDbg("SecExportRep::Key(): SET_PubKey");
break;
case CSSM_KEYCLASS_PRIVATE_KEY:
mExternType = kSecItemTypePrivateKey;
SecImpExpDbg("SecExportRep::Key(): SET_PrivKey");
break;
case CSSM_KEYCLASS_SESSION_KEY:
mExternType = kSecItemTypeSessionKey;
SecImpExpDbg("SecExportRep::Key(): SET_SessionKey");
break;
default:
SecImpExpDbg("SecExportRep::Key(): invalid KeyClass (%lu)",
(unsigned long)mCssmKey->KeyHeader.KeyClass);
MacOSError::throwMe(errSecInvalidItemRef);
}
mKeyAlg = mCssmKey->KeyHeader.AlgorithmId;
}
SecExport::Key::~Key()
{
}
OSStatus SecExport::Key::exportRep(
SecExternalFormat format,
SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, CFMutableDataRef outData, const char **pemHeader){
assert(outData != NULL);
assert(mKcItem != NULL);
assert(mCssmKey != NULL);
CssmAutoData descrData(Allocator::standard());
switch(format) {
case kSecFormatSSH:
case kSecFormatSSHv2:
case kSecFormatWrappedSSH:
impExpOpensshInferDescData((SecKeyRef)mKcItem, descrData);
break;
default:
break;
}
switch(format) {
case kSecFormatWrappedPKCS8:
return impExpPkcs8Export((SecKeyRef)mKcItem, flags, keyParams,
outData, pemHeader);
case kSecFormatWrappedOpenSSL:
return impExpWrappedKeyOpenSslExport((SecKeyRef)mKcItem, flags, keyParams,
outData, pemHeader, &mPemParamLines);
case kSecFormatWrappedSSH:
return impExpWrappedOpenSSHExport((SecKeyRef)mKcItem, flags, keyParams,
descrData, outData);
case kSecFormatWrappedLSH:
return errSecUnsupportedFormat;
default:
break;
}
OSStatus ortn = errSecSuccess;
CSSM_KEYBLOB_FORMAT blobForm;
switch(mExternType) {
case kSecItemTypePublicKey:
switch(mKeyAlg) {
case CSSM_ALGID_RSA:
*pemHeader = PEM_STRING_RSA_PUBLIC;
break;
case CSSM_ALGID_DH:
*pemHeader = PEM_STRING_DH_PUBLIC;
break;
case CSSM_ALGID_DSA:
*pemHeader = PEM_STRING_DSA_PUBLIC;
break;
case CSSM_ALGID_ECDSA:
*pemHeader = PEM_STRING_ECDSA_PUBLIC;
break;
default:
SecImpExpDbg("SecExportRep::exportRep unknown public key alg %lu",
(unsigned long)mKeyAlg);
return errSecUnsupportedFormat;
}
break;
case kSecItemTypePrivateKey:
switch(mKeyAlg) {
case CSSM_ALGID_RSA:
*pemHeader = PEM_STRING_RSA;
break;
case CSSM_ALGID_DH:
*pemHeader = PEM_STRING_DH_PRIVATE;
break;
case CSSM_ALGID_DSA:
*pemHeader = PEM_STRING_DSA;
break;
case CSSM_ALGID_ECDSA:
*pemHeader = PEM_STRING_ECDSA_PRIVATE;
break;
default:
SecImpExpDbg("SecExportRep::exportRep unknown private key alg "
"%lu", (unsigned long)mKeyAlg);
return errSecUnsupportedFormat;
}
break;
case kSecItemTypeSessionKey:
*pemHeader = PEM_STRING_SESSION;
break;
default:
assert(0);
return errSecInvalidItemRef;
}
CSSM_KEYCLASS keyClass;
ortn = impExpKeyForm(format, mExternType, mKeyAlg, &blobForm, &keyClass);
if(ortn) {
return ortn;
}
CSSM_ATTRIBUTE_TYPE formatAttrType = CSSM_ATTRIBUTE_NONE;
switch(mExternType) {
case kSecItemTypePrivateKey:
formatAttrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
break;
case kSecItemTypePublicKey:
formatAttrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
break;
default:
break;
}
CSSM_CSP_HANDLE cspHand;
ortn = SecKeyGetCSPHandle((SecKeyRef)mKcItem, &cspHand);
if(ortn) {
SecImpExpDbg("SecExportRep::exportRep SecKeyGetCSPHandle error");
return ortn;
}
CSSM_KEY wrappedKey;
memset(&wrappedKey, 0, sizeof(wrappedKey));
const CSSM_DATA &dd = descrData;
ortn = impExpExportKeyCommon(cspHand,
(SecKeyRef)mKcItem,
NULL, &wrappedKey, CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
CSSM_PADDING_NONE,
CSSM_KEYBLOB_WRAPPED_FORMAT_NONE,
formatAttrType,
blobForm,
&dd, NULL);
if(ortn == CSSM_OK) {
CFDataAppendBytes(outData, wrappedKey.KeyData.Data, wrappedKey.KeyData.Length);
}
CSSM_FreeKey(cspHand, NULL, &wrappedKey, CSSM_FALSE);
return ortn;
}
#pragma mark --- Certificate External rep ---
SecExport::Cert::Cert(
CFTypeRef kcItemRef) :
SecExportRep(kcItemRef)
{
mExternType = kSecItemTypeCertificate;
}
SecExport::Cert::~Cert()
{
}
OSStatus SecExport::Cert::exportRep(
SecExternalFormat format,
SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, CFMutableDataRef outData, const char **pemHeader){
assert(outData != NULL);
assert(mKcItem != NULL);
switch(format) {
case kSecFormatUnknown: case kSecFormatX509Cert: break;
default:
SecImpExpDbg("SecExportRep::exportRep unsupported format for cert");
return errSecUnsupportedFormat;
}
CFDataRef cdata = SecCertificateCopyData((SecCertificateRef)mKcItem);
if(!cdata) {
SecImpExpDbg("SecExportRep::exportRep SecCertificateGetData error");
return errSecUnsupportedFormat;
}
CFDataAppendBytes(outData, CFDataGetBytePtr(cdata), CFDataGetLength(cdata));
CFRelease(cdata);
*pemHeader = PEM_STRING_X509;
return errSecSuccess;
}
#pragma mark --- SecImportRep: Representation of an external object on import ---
SecImportRep::SecImportRep(
CFDataRef external,
SecExternalItemType externType, SecExternalFormat externFormat, CSSM_ALGORITHMS keyAlg, CFArrayRef pemParamLines ) :
mPrintName(NULL),
mExternal(external),
mExternType(externType),
mExternFormat(externFormat),
mKeyAlg(keyAlg),
mPemParamLines(pemParamLines)
{
CFRetain(mExternal);
}
SecImportRep::~SecImportRep()
{
if(mPrintName) {
free(mPrintName);
}
if(mExternal) {
CFRelease(mExternal);
}
if(mPemParamLines) {
CFRelease(mPemParamLines);
}
}
OSStatus SecImportRep::importRep(
SecKeychainRef importKeychain, CSSM_CSP_HANDLE cspHand, SecItemImportExportFlags flags,
const SecKeyImportExportParameters *keyParams, ImpPrivKeyImportState &keyImportState, CFMutableArrayRef outArray) {
assert((mExternType != kSecItemTypeUnknown) &&
(mExternFormat != kSecFormatUnknown));
if((mExternal == NULL) || (CFDataGetLength(mExternal) == 0)) {
return errSecParam;
}
switch(mExternFormat) {
case kSecFormatPKCS12:
return impExpPkcs12Import(mExternal, flags, keyParams,
keyImportState, importKeychain, cspHand, outArray);
case kSecFormatX509Cert:
case kSecFormatPKCS7:
{
OSStatus rx = impExpPkcs7Import(mExternal, flags, keyParams, importKeychain,
outArray);
if (rx == errSecUnknownFormat)
{
CSSM_DATA cdata;
cdata.Data = (uint8 *)CFDataGetBytePtr(mExternal);
cdata.Length = (CSSM_SIZE)CFDataGetLength(mExternal);
return impExpImportCertCommon(&cdata, importKeychain, outArray);
}
return rx;
}
case kSecFormatNetscapeCertSequence:
return impExpNetscapeCertImport(mExternal, flags, keyParams, importKeychain,
outArray);
default:
break;
}
if((mExternType == kSecItemTypeCertificate) ||
(mExternType == kSecItemTypeAggregate)) {
SecImpExpDbg("SecImportRep::importRep screwup");
return errSecUnimplemented;
}
if((mExternType == kSecItemTypePrivateKey) && (keyImportState == PIS_NoMore)) {
return errSecMultiplePrivKeys;
}
switch(mExternFormat) {
case kSecFormatSSH:
case kSecFormatWrappedSSH:
case kSecFormatSSHv2:
mPrintName = impExpOpensshInferPrintName(mExternal, mExternType, mExternFormat);
break;
default:
break;
}
OSStatus ortn = errSecSuccess;
switch(mExternFormat) {
case kSecFormatOpenSSL:
case kSecFormatSSH:
case kSecFormatSSHv2:
case kSecFormatBSAFE:
case kSecFormatRawKey:
ortn = impExpImportRawKey(mExternal, mExternFormat, mExternType,
mKeyAlg, importKeychain, cspHand, flags, keyParams, mPrintName, outArray);
break;
case kSecFormatWrappedPKCS8:
ortn = impExpPkcs8Import(mExternal, importKeychain, cspHand, flags,
keyParams, outArray);
break;
case kSecFormatWrappedOpenSSL:
ortn = importWrappedKeyOpenssl(importKeychain, cspHand, flags, keyParams,
outArray);
break;
case kSecFormatWrappedSSH:
ortn = impExpWrappedOpenSSHImport(mExternal, importKeychain, cspHand,
flags, keyParams, mPrintName, outArray);
break;
case kSecFormatWrappedLSH:
default:
return errSecUnknownFormat;
}
if((ortn == errSecSuccess) && (keyImportState == PIS_AllowOne)) {
keyImportState = PIS_NoMore;
}
return ortn;
}