X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_keychain/lib/SecImportExportUtils.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/SecImportExportUtils.cpp b/Security/libsecurity_keychain/lib/SecImportExportUtils.cpp deleted file mode 100644 index e0f17768..00000000 --- a/Security/libsecurity_keychain/lib/SecImportExportUtils.cpp +++ /dev/null @@ -1,972 +0,0 @@ -/* - * Copyright (c) 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@ - * - * SecImportExportUtils.cpp - misc. utilities for import/export module - */ - -#include "SecImportExportUtils.h" -#include "SecImportExportAgg.h" -#include "SecImportExportCrypto.h" -#include "SecIdentityPriv.h" -#include "SecItem.h" -#include -#include -#pragma mark --- Debug support --- - -#ifndef NDEBUG - -const char *impExpExtFormatStr( - SecExternalFormat format) -{ - switch(format) { - case kSecFormatUnknown: return "kSecFormatUnknown"; - case kSecFormatOpenSSL: return "kSecFormatOpenSSL"; - case kSecFormatSSH: return "kSecFormatSSH"; - case kSecFormatBSAFE: return "kSecFormatBSAFE"; - case kSecFormatRawKey: return "kSecFormatRawKey"; - case kSecFormatWrappedPKCS8: return "kSecFormatWrappedPKCS8"; - case kSecFormatWrappedOpenSSL: return "kSecFormatWrappedOpenSSL"; - case kSecFormatWrappedSSH: return "kSecFormatWrappedSSH"; - case kSecFormatWrappedLSH: return "kSecFormatWrappedLSH"; - case kSecFormatX509Cert: return "kSecFormatX509Cert"; - case kSecFormatPEMSequence: return "kSecFormatPEMSequence"; - case kSecFormatPKCS7: return "kSecFormatPKCS7"; - case kSecFormatPKCS12: return "kSecFormatPKCS12"; - case kSecFormatNetscapeCertSequence: return "kSecFormatNetscapeCertSequence"; - default: return "UNKNOWN FORMAT ENUM"; - } -} - -const char *impExpExtItemTypeStr( - SecExternalItemType itemType) -{ - switch(itemType) { - case kSecItemTypeUnknown: return "kSecItemTypeUnknown"; - case kSecItemTypePrivateKey: return "kSecItemTypePrivateKey"; - case kSecItemTypePublicKey: return "kSecItemTypePublicKey"; - case kSecItemTypeSessionKey: return "kSecItemTypeSessionKey"; - case kSecItemTypeCertificate: return "kSecItemTypeCertificate"; - case kSecItemTypeAggregate: return "kSecItemTypeAggregate"; - default: return "UNKNOWN ITEM TYPE ENUM"; - } -} -#endif /* NDEBUG */ - -/* - * Parse file extension and attempt to map it to format and type. Returns true - * on success. - */ -bool impExpImportParseFileExten( - CFStringRef fstr, - SecExternalFormat *inputFormat, // RETURNED - SecExternalItemType *itemType) // RETURNED -{ - if(fstr == NULL) { - /* nothing to work with */ - return false; - } - if(CFStringHasSuffix(fstr, CFSTR(".cer")) || - CFStringHasSuffix(fstr, CFSTR(".crt"))) { - *inputFormat = kSecFormatX509Cert; - *itemType = kSecItemTypeCertificate; - SecImpInferDbg("Inferring kSecFormatX509Cert from file name"); - return true; - } - if(CFStringHasSuffix(fstr, CFSTR(".p12")) || - CFStringHasSuffix(fstr, CFSTR(".pfx"))) { - *inputFormat = kSecFormatPKCS12; - *itemType = kSecItemTypeAggregate; - SecImpInferDbg("Inferring kSecFormatPKCS12 from file name"); - return true; - } - - /* Get extension, look for key indicators as substrings */ - CFURLRef url = CFURLCreateWithString(NULL, fstr, NULL); - if(url == NULL) { - SecImpInferDbg("impExpImportParseFileExten: error creating URL"); - return false; - } - CFStringRef exten = CFURLCopyPathExtension(url); - CFRelease(url); - if(exten == NULL) { - /* no extension, app probably passed in only an extension */ - exten = fstr; - CFRetain(exten); - } - bool ortn = false; - CFRange cfr; - cfr = CFStringFind(exten, CFSTR("p7"), kCFCompareCaseInsensitive); - if(cfr.length != 0) { - *inputFormat = kSecFormatPKCS7; - *itemType = kSecItemTypeAggregate; - SecImpInferDbg("Inferring kSecFormatPKCS7 from file name"); - ortn = true; - } - if(!ortn) { - cfr = CFStringFind(exten, CFSTR("p8"), kCFCompareCaseInsensitive); - if(cfr.length != 0) { - *inputFormat = kSecFormatWrappedPKCS8; - *itemType = kSecItemTypePrivateKey; - SecImpInferDbg("Inferring kSecFormatPKCS8 from file name"); - ortn = true; - } - } - CFRelease(exten); - return ortn; -} - -/* do a [NSString stringByDeletingPathExtension] equivalent */ -CFStringRef impExpImportDeleteExtension( - CFStringRef fileStr) -{ - CFDataRef fileStrData = CFStringCreateExternalRepresentation(NULL, fileStr, - kCFStringEncodingUTF8, 0); - if(fileStrData == NULL) { - return NULL; - } - - CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(NULL, - CFDataGetBytePtr(fileStrData), CFDataGetLength(fileStrData), false); - if(urlRef == NULL) { - CFRelease(fileStrData); - return NULL; - } - CFURLRef rtnUrl = CFURLCreateCopyDeletingPathExtension(NULL, urlRef); - CFStringRef rtnStr = NULL; - CFRelease(urlRef); - if(rtnUrl) { - rtnStr = CFURLGetString(rtnUrl); - CFRetain(rtnStr); - CFRelease(rtnUrl); - } - CFRelease(fileStrData); - return rtnStr; -} - -#pragma mark --- mapping of external format to CDSA formats --- - -/* - * For the record, here is the mapping of SecExternalFormat, algorithm, and key - * class to CSSM-style key format (CSSM_KEYBLOB_FORMAT - - * CSSM_KEYBLOB_RAW_FORMAT_X509, etc). The entries in the table are the - * last component of a CSSM_KEYBLOB_FORMAT. Format kSecFormatUnknown means - * "default for specified class and algorithm", which is currently the - * same as kSecFormatOpenSSL. - * - * algorithm/class - * RSA DSA DH - * ---------------- ---------------- ---------------- - * SecExternalFormat priv pub priv pub priv pub - * ----------------- ------- ------- ------- ------- ------- ------- - * kSecFormatOpenSSL PKCS1 X509 OPENSSL X509 PKCS3 X509 - * kSecFormatBSAFE PKCS8 PKCS1 FIPS186 FIPS186 PKCS8 not supported - * kSecFormatUnknown PKCS1 X509 OPENSSL X509 PKCS3 X509 - * kSecFormatSSH SSH SSH n/s n/s n/s n/s - * kSecFormatSSHv2 n/s SSH2 n/s SSH2 n/s n/s - * - * The only external format supported for ECDSA and ECDH keys is kSecFormatOpenSSL, - * which translates to OPENSSL for private keys and X509 for public keys. - */ - -/* Arrays expressing the above table. */ - -/* l.s. dimension is pub/priv for one alg */ -typedef struct { - CSSM_KEYBLOB_FORMAT priv; - CSSM_KEYBLOB_FORMAT pub; -} algForms; - -/* - * indices into array of algForms defining all algs' formats for a given - * SecExternalFormat - */ -#define SIE_ALG_RSA 0 -#define SIE_ALG_DSA 1 -#define SIE_ALG_DH 2 -#define SIE_ALG_ECDSA 3 -#define SIE_ALG_LAST SIE_ALG_ECDSA -#define SIE_NUM_ALGS (SIE_ALG_LAST + 1) - -/* kSecFormatOpenSSL */ -static algForms opensslAlgForms[SIE_NUM_ALGS] = -{ - { CSSM_KEYBLOB_RAW_FORMAT_PKCS1, CSSM_KEYBLOB_RAW_FORMAT_X509 }, // RSA - { CSSM_KEYBLOB_RAW_FORMAT_OPENSSL, CSSM_KEYBLOB_RAW_FORMAT_X509 }, // DSA - { CSSM_KEYBLOB_RAW_FORMAT_PKCS3, CSSM_KEYBLOB_RAW_FORMAT_X509 }, // D-H - { CSSM_KEYBLOB_RAW_FORMAT_OPENSSL, CSSM_KEYBLOB_RAW_FORMAT_X509 }, // ECDSA -}; - -/* kSecFormatBSAFE */ -static algForms bsafeAlgForms[SIE_NUM_ALGS] = -{ - { CSSM_KEYBLOB_RAW_FORMAT_PKCS8, CSSM_KEYBLOB_RAW_FORMAT_PKCS1 }, // RSA - { CSSM_KEYBLOB_RAW_FORMAT_FIPS186, CSSM_KEYBLOB_RAW_FORMAT_FIPS186 }, // DSA - { CSSM_KEYBLOB_RAW_FORMAT_PKCS8, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // D-H - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // ECDSA not supported -}; - -/* kSecFormatSSH (v1) */ -static algForms ssh1AlgForms[SIE_NUM_ALGS] = -{ - { CSSM_KEYBLOB_RAW_FORMAT_OPENSSH, CSSM_KEYBLOB_RAW_FORMAT_OPENSSH }, // RSA only - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // DSA not supported - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // D-H not supported - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // ECDSA not supported -}; - -/* kSecFormatSSHv2 */ -static algForms ssh2AlgForms[SIE_NUM_ALGS] = -{ - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2 }, // RSA - public only - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2 }, // DSA - public only - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // D-H not supported - { CSSM_KEYBLOB_RAW_FORMAT_NONE, CSSM_KEYBLOB_RAW_FORMAT_NONE }, // ECDSA not supported -}; - -/* - * This routine performs a lookup into the above 3-dimensional array to - * map {algorithm, class, SecExternalFormat} to a CSSM_KEYBLOB_FORMAT. - * Returns errSecUnsupportedFormat in the rare appropriate case. - */ -OSStatus impExpKeyForm( - SecExternalFormat externForm, - SecExternalItemType itemType, - CSSM_ALGORITHMS alg, - CSSM_KEYBLOB_FORMAT *cssmForm, // RETURNED - CSSM_KEYCLASS *cssmClass) // RETRUNED -{ - if(itemType == kSecItemTypeSessionKey) { - /* special trivial case */ - /* FIXME ensure caller hasn't specified bogus format */ - *cssmForm = CSSM_KEYBLOB_RAW_FORMAT_NONE; - *cssmClass = CSSM_KEYCLASS_SESSION_KEY; - return errSecSuccess; - } - if(externForm == kSecFormatUnknown) { - /* default is openssl */ - externForm = kSecFormatOpenSSL; - } - - unsigned algDex; - switch(alg) { - case CSSM_ALGID_RSA: - algDex = SIE_ALG_RSA; - break; - case CSSM_ALGID_DSA: - algDex = SIE_ALG_DSA; - break; - case CSSM_ALGID_DH: - algDex = SIE_ALG_DH; - break; - case CSSM_ALGID_ECDSA: - algDex = SIE_ALG_ECDSA; - break; - default: - return CSSMERR_CSP_INVALID_ALGORITHM; - } - const algForms *forms; - switch(externForm) { - case kSecFormatOpenSSL: - forms = opensslAlgForms; - break; - case kSecFormatBSAFE: - forms = bsafeAlgForms; - break; - case kSecFormatSSH: - forms = ssh1AlgForms; - break; - case kSecFormatSSHv2: - forms = ssh2AlgForms; - break; - default: - return errSecUnsupportedFormat; - } - CSSM_KEYBLOB_FORMAT form = CSSM_KEYBLOB_RAW_FORMAT_NONE; - switch(itemType) { - case kSecItemTypePrivateKey: - form = forms[algDex].priv; - *cssmClass = CSSM_KEYCLASS_PRIVATE_KEY; - break; - case kSecItemTypePublicKey: - form = forms[algDex].pub; - *cssmClass = CSSM_KEYCLASS_PUBLIC_KEY; - break; - default: - return errSecUnsupportedFormat; - } - if(form == CSSM_KEYBLOB_RAW_FORMAT_NONE) { - /* not in the tables - abort */ - return errSecUnsupportedFormat; - } - else { - *cssmForm = form; - return errSecSuccess; - } -} - -/* - * Given a raw key blob and zero to three known parameters (type, format, - * algorithm), figure out all parameters. Used for private and public keys. - */ -static bool impExpGuessKeyParams( - CFDataRef keyData, - SecExternalFormat *externForm, // IN/OUT - SecExternalItemType *itemType, // IN/OUT - CSSM_ALGORITHMS *keyAlg) // IN/OUT -{ - /* CSSM alg list: RSA, DSA, DH, ECDSA */ - CSSM_ALGORITHMS minAlg = CSSM_ALGID_RSA; - CSSM_ALGORITHMS maxAlg = CSSM_ALGID_ECDSA; - SecExternalFormat minForm = kSecFormatOpenSSL; // then SSH, BSAFE, then... - SecExternalFormat maxForm = kSecFormatSSHv2; - SecExternalItemType minType = kSecItemTypePrivateKey; // just two - SecExternalItemType maxType = kSecItemTypePublicKey; - - - if(keyData == NULL || CFDataGetLength(keyData) == 0){ - MacOSError::throwMe(errSecUnsupportedKeySize); - } - - switch(*externForm) { - case kSecFormatUnknown: - break; // run through all formats - case kSecFormatOpenSSL: - case kSecFormatSSH: - case kSecFormatSSHv2: - case kSecFormatBSAFE: - minForm = maxForm = *externForm; // just test this one - break; - default: - return false; - } - switch(*itemType) { - case kSecItemTypeUnknown: - break; - case kSecItemTypePrivateKey: - case kSecItemTypePublicKey: - minType = maxType = *itemType; - break; - default: - return false; - } - switch(*keyAlg) { - case CSSM_ALGID_NONE: - break; - case CSSM_ALGID_RSA: - case CSSM_ALGID_DSA: - case CSSM_ALGID_DH: - case CSSM_ALGID_ECDSA: - minAlg = maxAlg = *keyAlg; - break; - default: - return false; - } - - CSSM_ALGORITHMS theAlg; - SecExternalFormat theForm; - SecExternalItemType theType; - CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_TRUE); - if(cspHand == 0) { - return CSSMERR_CSSM_ADDIN_LOAD_FAILED; - } - - /* - * Iterate through all set of enabled {alg, type, format}. - * We do not assume that any of the enums are sequential hence this - * odd iteration algorithm.... - */ - bool ourRtn = false; - for(theAlg=minAlg; ; ) { - for(theForm=minForm; ; ) { - for(theType=minType; ; ) { - - /* do super lightweight null unwrap to parse */ - OSStatus ortn = impExpImportRawKey(keyData, - theForm, theType, theAlg, - NULL, // no keychain - cspHand, - 0, // no flags - NULL, // no key params - NULL, // no printName - NULL); // no returned items - if(ortn == errSecSuccess) { - *externForm = theForm; - *itemType = theType; - *keyAlg = theAlg; - ourRtn = true; - goto done; - } - - /* next type or break if we're done */ - if(theType == maxType) { - break; - } - else switch(theType) { - case kSecItemTypePrivateKey: - theType = kSecItemTypePublicKey; - break; - default: - assert(0); - ourRtn = false; - goto done; - } - } /* for each class/type */ - - /* next format or break if we're done */ - if(theForm == maxForm) { - break; - } - else switch(theForm) { - case kSecFormatOpenSSL: - theForm = kSecFormatSSH; - break; - case kSecFormatSSH: - theForm = kSecFormatBSAFE; - break; - case kSecFormatBSAFE: - theForm = kSecFormatSSHv2; - break; - default: - assert(0); - ourRtn = false; - goto done; - } - } /* for each format */ - - /* next alg or break if we're done */ - if(theAlg == maxAlg) { - break; - } - else switch(theAlg) { - case CSSM_ALGID_RSA: - theAlg = CSSM_ALGID_DSA; - break; - case CSSM_ALGID_DSA: - theAlg = CSSM_ALGID_DH; - break; - case CSSM_ALGID_DH: - theAlg = CSSM_ALGID_ECDSA; - break; - default: - /* i.e. CSSM_ALGID_ECDSA, we already broke at theAlg == maxAlg */ - assert(0); - ourRtn = false; - goto done; - } - } /* for each alg */ -done: - cuCspDetachUnload(cspHand, CSSM_TRUE); - return ourRtn; -} - -/* - * Guess an incoming blob's type, format and (for keys only) algorithm - * by examining its contents. Returns true on success, in which case - * *inputFormat, *itemType, and *keyAlg are all valid. Caller optionally - * passes in valid values any number of these as a clue. - */ -bool impExpImportGuessByExamination( - CFDataRef inData, - SecExternalFormat *inputFormat, // may be kSecFormatUnknown on entry - SecExternalItemType *itemType, // may be kSecItemTypeUnknown on entry - CSSM_ALGORITHMS *keyAlg) // CSSM_ALGID_NONE - unknown -{ - if( ( (*inputFormat == kSecFormatUnknown) || - (*inputFormat == kSecFormatX509Cert) - ) && - ( (*itemType == kSecItemTypeUnknown) || - (*itemType == kSecItemTypeCertificate) ) ) { - /* - * See if it parses as a cert - */ - CSSM_CL_HANDLE clHand = cuClStartup(); - if(clHand == 0) { - return CSSMERR_CSSM_ADDIN_LOAD_FAILED; - } - CSSM_HANDLE cacheHand; - CSSM_RETURN crtn; - CSSM_DATA cdata = { CFDataGetLength(inData), - (uint8 *)CFDataGetBytePtr(inData) }; - crtn = CSSM_CL_CertCache(clHand, &cdata, &cacheHand); - bool brtn = false; - if(crtn == CSSM_OK) { - *inputFormat = kSecFormatX509Cert; - *itemType = kSecItemTypeCertificate; - SecImpInferDbg("Inferred kSecFormatX509Cert via CL"); - CSSM_CL_CertAbortCache(clHand, cacheHand); - brtn = true; - } - cuClDetachUnload(clHand); - if(brtn) { - return true; - } - } - /* TBD: need way to inquire of P12 lib if this is a valid-looking PFX */ - - if( ( (*inputFormat == kSecFormatUnknown) || - (*inputFormat == kSecFormatNetscapeCertSequence) - ) && - ( (*itemType == kSecItemTypeUnknown) || - (*itemType == kSecItemTypeAggregate) ) ) { - /* See if it's a netscape cert sequence */ - CSSM_RETURN crtn = impExpNetscapeCertImport(inData, 0, NULL, NULL, NULL); - if(crtn == CSSM_OK) { - *inputFormat = kSecFormatNetscapeCertSequence; - *itemType = kSecItemTypeAggregate; - SecImpInferDbg("Inferred netscape-cert-sequence by decoding"); - return true; - } - } - - /* See if it's a key */ - return impExpGuessKeyParams(inData, inputFormat, itemType, keyAlg); -} - -#pragma mark --- Key Import support --- - -/* - * Given a context specified via a CSSM_CC_HANDLE, add a new - * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType, - * AttributeLength, and an untyped pointer. - */ -CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle, - uint32 AttributeType, - uint32 AttributeLength, - const void *AttributePtr) -{ - CSSM_CONTEXT_ATTRIBUTE newAttr; - - newAttr.AttributeType = AttributeType; - newAttr.AttributeLength = AttributeLength; - newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr; - return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr); -} - -/* - * Free memory via specified plugin's app-level allocator - */ -void impExpFreeCssmMemory( - CSSM_HANDLE hand, - void *p) -{ - CSSM_API_MEMORY_FUNCS memFuncs; - CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs); - if(crtn) { - return; - } - memFuncs.free_func(p, memFuncs.AllocRef); -} - -/* - * Calculate digest of any CSSM_KEY. Unlike older implementations - * of this logic, you can actually calculate the public key hash - * on any class of key, any format, raw CSP or CSPDL (though if - * you're using the CSPDL, the key has to be a reference key - * in that CSPDL session). - * - * Caller must free keyDigest->Data using impExpFreeCssmMemory() since - * this is allocated by the CSP's app-specified allocator. - */ -CSSM_RETURN impExpKeyDigest( - CSSM_CSP_HANDLE cspHand, - CSSM_KEY_PTR key, - CSSM_DATA_PTR keyDigest) // contents allocd and RETURNED -{ - CSSM_DATA_PTR localDigest; - CSSM_CC_HANDLE ccHand; - - CSSM_RETURN crtn = CSSM_CSP_CreatePassThroughContext(cspHand, - key, - &ccHand); - if(crtn) { - return crtn; - } - crtn = CSSM_CSP_PassThrough(ccHand, - CSSM_APPLECSP_KEYDIGEST, - NULL, - (void **)&localDigest); - if(crtn) { - SecImpExpDbg("CSSM_CSP_PassThrough(KEY_DIGEST) failure"); - } - else { - /* - * Give caller the Data referent and we'll free the - * CSSM_DATA struct itswelf. - */ - *keyDigest = *localDigest; - impExpFreeCssmMemory(cspHand, localDigest); - } - CSSM_DeleteContext(ccHand); - return crtn; -} - - -/* - * Given a CFTypeRef passphrase which may be a CFDataRef or a CFStringRef, - * return a refcounted CFStringRef suitable for use with the PKCS12 library. - * PKCS12 passphrases in CFData format must be UTF8 encoded. - */ -OSStatus impExpPassphraseToCFString( - CFTypeRef passin, - CFStringRef *passout) // may be the same as passin, but refcounted -{ - if(CFGetTypeID(passin) == CFStringGetTypeID()) { - CFStringRef passInStr = (CFStringRef)passin; - CFRetain(passInStr); - *passout = passInStr; - return errSecSuccess; - } - else if(CFGetTypeID(passin) == CFDataGetTypeID()) { - CFDataRef cfData = (CFDataRef)passin; - CFIndex len = CFDataGetLength(cfData); - CFStringRef cfStr = CFStringCreateWithBytes(NULL, - CFDataGetBytePtr(cfData), len, kCFStringEncodingUTF8, true); - if(cfStr == NULL) { - SecImpExpDbg("Passphrase not in UTF8 format"); - return errSecParam; - } - *passout = cfStr; - return errSecSuccess; - } - else { - SecImpExpDbg("Passphrase not CFData or CFString"); - return errSecParam; - } -} - -/* - * Given a CFTypeRef passphrase which may be a CFDataRef or a CFStringRef, - * return a refcounted CFDataRef whose bytes are suitable for use with - * PKCS5 (v1.5 and v2.0) key derivation. - */ -OSStatus impExpPassphraseToCFData( - CFTypeRef passin, - CFDataRef *passout) // may be the same as passin, but refcounted -{ - if(CFGetTypeID(passin) == CFDataGetTypeID()) { - CFDataRef passInData = (CFDataRef)passin; - CFRetain(passInData); - *passout = passInData; - return errSecSuccess; - } - else if(CFGetTypeID(passin) == CFStringGetTypeID()) { - CFStringRef passInStr = (CFStringRef)passin; - CFDataRef outData; - outData = CFStringCreateExternalRepresentation(NULL, - passInStr, - kCFStringEncodingUTF8, - 0); // lossByte 0 ==> no loss allowed - if(outData == NULL) { - /* Well try with lossy conversion */ - SecImpExpDbg("Trying lossy conversion of CFString passphrase to UTF8"); - outData = CFStringCreateExternalRepresentation(NULL, - passInStr, - kCFStringEncodingUTF8, - 1); - if(outData == NULL) { - SecImpExpDbg("Failure on conversion of CFString passphrase to UTF8"); - /* what do we do now, Batman? */ - return errSecParam; - } - } - *passout = outData; - return errSecSuccess; - } - else { - SecImpExpDbg("Passphrase not CFData or CFString"); - return errSecParam; - } -} - -/* -* Add a CFString to a crypto context handle. -*/ -static CSSM_RETURN impExpAddStringAttr( - CSSM_CC_HANDLE ccHand, - CFStringRef str, - CSSM_ATTRIBUTE_TYPE attrType) -{ - /* CFStrings are passed as external rep in UTF8 encoding by convention */ - CFDataRef outData; - outData = CFStringCreateExternalRepresentation(NULL, - str, kCFStringEncodingUTF8, 0); // lossByte 0 ==> no loss allowed - if(outData == NULL) { - SecImpExpDbg("impExpAddStringAttr: bad string format"); - return errSecParam; - } - - CSSM_DATA attrData; - attrData.Data = (uint8 *)CFDataGetBytePtr(outData); - attrData.Length = CFDataGetLength(outData); - CSSM_RETURN crtn = impExpAddContextAttribute(ccHand, attrType, sizeof(CSSM_DATA), - &attrData); - CFRelease(outData); - if(crtn) { - SecImpExpDbg("impExpAddStringAttr: CSSM_UpdateContextAttributes error"); - } - return crtn; -} - -/* - * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result. - */ -static CSSM_RETURN impExpCreatePassKey( - const SecKeyImportExportParameters *keyParams, // required - CSSM_CSP_HANDLE cspHand, // MUST be CSPDL - impExpVerifyPhrase verifyPhrase, // for secure passphrase - CSSM_KEY_PTR *passKey) // mallocd and RETURNED -{ - CSSM_RETURN crtn; - CSSM_CC_HANDLE ccHand; - uint32 verifyAttr; - CSSM_DATA dummyLabel; - CSSM_KEY_PTR ourKey = NULL; - - SecImpExpDbg("Generating secure passphrase key"); - ourKey = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY)); - if(ourKey == NULL) { - return errSecAllocate; - } - memset(ourKey, 0, sizeof(CSSM_KEY)); - - crtn = CSSM_CSP_CreateKeyGenContext(cspHand, - CSSM_ALGID_SECURE_PASSPHRASE, - 4, // keySizeInBits must be non zero - NULL, // Seed - NULL, // Salt - NULL, // StartDate - NULL, // EndDate - NULL, // Params - &ccHand); - if(crtn) { - SecImpExpDbg("impExpCreatePassKey: CSSM_CSP_CreateKeyGenContext error"); - return crtn; - } - /* subsequent errors to errOut: */ - - /* additional context attributes specific to this type of key gen */ - assert(keyParams != NULL); // or we wouldn't be here - if(keyParams->alertTitle != NULL) { - crtn = impExpAddStringAttr(ccHand, keyParams->alertTitle, - CSSM_ATTRIBUTE_ALERT_TITLE); - if(crtn) { - goto errOut; - } - } - if(keyParams->alertPrompt != NULL) { - crtn = impExpAddStringAttr(ccHand, keyParams->alertPrompt, - CSSM_ATTRIBUTE_PROMPT); - if(crtn) { - goto errOut; - } - } - verifyAttr = (verifyPhrase == VP_Export) ? 1 : 0; - crtn = impExpAddContextAttribute(ccHand, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE, - sizeof(uint32), (const void *)((size_t) verifyAttr)); - if(crtn) { - SecImpExpDbg("impExpCreatePassKey: CSSM_UpdateContextAttributes error"); - goto errOut; - } - - dummyLabel.Data = (uint8 *)"Secure Passphrase"; - dummyLabel.Length = strlen((char *)dummyLabel.Data); - - crtn = CSSM_GenerateKey(ccHand, - CSSM_KEYUSE_ANY, - CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, - &dummyLabel, - NULL, // ACL - ourKey); - if(crtn) { - SecImpExpDbg("impExpCreatePassKey: CSSM_GenerateKey error"); - } -errOut: - CSSM_DeleteContext(ccHand); - if(crtn == CSSM_OK) { - *passKey = ourKey; - } - else if(ourKey != NULL) { - free(ourKey); - } - return crtn; -} - -/* - * Obtain passphrase, given a SecKeyImportExportParameters. - * - * Passphrase comes from one of two places: app-specified, in - * SecKeyImportExportParameters.passphrase (either as CFStringRef - * or CFDataRef); or via the secure passphrase mechanism. - * - * Passphrase is returned in AT MOST one of two forms: - * - * -- Secure passphrase is returned as a CSSM_KEY_PTR, which the - * caller must CSSM_FreeKey later as well as free()ing the actual - * CSSM_KEY_PTR. - * -- CFTypeRef for app-supplied passphrases. This can be one of - * two types: - * - * -- CFStringRef, for use with P12 - * -- CFDataRef, for more general use (e.g. for PKCS5). - * - * In either case the caller must CFRelease the result. - */ -OSStatus impExpPassphraseCommon( - const SecKeyImportExportParameters *keyParams, - CSSM_CSP_HANDLE cspHand, // MUST be CSPDL, for passKey generation - impExpPassphraseForm phraseForm, - impExpVerifyPhrase verifyPhrase, // for secure passphrase - CFTypeRef *phrase, // RETURNED, or - CSSM_KEY_PTR *passKey) // mallocd and RETURNED -{ - assert(keyParams != NULL); - - /* Give precedence to secure passphrase */ - if(keyParams->flags & kSecKeySecurePassphrase) { - assert(passKey != NULL); - return impExpCreatePassKey(keyParams, cspHand, verifyPhrase, passKey); - } - else if(keyParams->passphrase != NULL) { - CFTypeRef phraseOut; - OSStatus ortn; - assert(phrase != NULL); - switch(phraseForm) { - case SPF_String: - ortn = impExpPassphraseToCFString(keyParams->passphrase, - (CFStringRef *)&phraseOut); - break; - case SPF_Data: - ortn = impExpPassphraseToCFData(keyParams->passphrase, - (CFDataRef *)&phraseOut); - break; - default: - /* only called internally */ - assert(0); - ortn = errSecParam; - } - if(ortn == errSecSuccess) { - *phrase = phraseOut; - } - return ortn; - } - else { - return errSecPassphraseRequired; - } -} - -static void ToggleKeyAttribute( - CFArrayRef keyAttrs, - CFTypeRef attr, - CSSM_KEYATTR_FLAGS mask, - CSSM_KEYATTR_FLAGS &result) -{ - // If the keyAttrs array contains the given attribute, - // set the corresponding keyattr flags, otherwise clear them. - // (Note: caller verifies that keyAttrs is not NULL.) - CFIndex numItems = CFArrayGetCount(keyAttrs); - result &= ~(mask); - if (numItems > 0) { - CFRange range = CFRangeMake(0, numItems); - if (CFArrayContainsValue(keyAttrs, range, attr)) - result |= mask; - } -} - -CSSM_KEYATTR_FLAGS ConvertArrayToKeyAttributes(SecKeyRef aKey, CFArrayRef keyAttrs) -{ - CSSM_KEYATTR_FLAGS result = CSSM_KEYATTR_RETURN_DEFAULT; - - if (aKey) { - const CSSM_KEY* cssmKey = NULL; - if (errSecSuccess == SecKeyGetCSSMKey(aKey, &cssmKey)) - result = cssmKey->KeyHeader.KeyAttr; - } - - if (!keyAttrs) - return result; - - CFMutableArrayRef attrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFIndex idx, count = CFArrayGetCount(keyAttrs); - for (idx=0; idxversion = newPtr->version; - oldPtr->flags = newPtr->flags; - oldPtr->passphrase = newPtr->passphrase; - oldPtr->alertTitle = newPtr->alertTitle; - oldPtr->alertPrompt = newPtr->alertPrompt; - oldPtr->accessRef = newPtr->accessRef; - oldPtr->keyUsage = ConvertArrayToKeyUsage(newPtr->keyUsage); - oldPtr->keyAttributes = ConvertArrayToKeyAttributes(aKey, newPtr->keyAttributes); - result = true; - } - return result; -} -