extern "C" PAL_X509ContentType AppleCryptoNative_X509GetContentType(uint8_t* pbData, int32_t cbData) { if (pbData == nullptr || cbData < 0) return PAL_X509Unknown; CFDataRef cfData = CFDataCreateWithBytesNoCopy(nullptr, pbData, cbData, kCFAllocatorNull); if (cfData == nullptr) return PAL_X509Unknown; // The sniffing order is: // * X509 DER // * PKCS7 PEM/DER // * PKCS12 DER (or PEM if Apple has non-standard support for that) // * X509 PEM (or DER, but that already matched) // // If the X509 PEM check is done first SecItemImport will erroneously match // some PKCS#7 blobs and say they were certificates. // // Likewise, if the X509 DER check isn't done first, Apple will report it as // being a PKCS#7. SecCertificateRef certref = SecCertificateCreateWithData(nullptr, cfData); if (certref != nullptr) { CFRelease(certref); return PAL_Certificate; } SecExternalFormat dataFormat = kSecFormatPKCS7; SecExternalFormat actualFormat = dataFormat; SecExternalItemType itemType = kSecItemTypeAggregate; SecExternalItemType actualType = itemType; OSStatus osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, nullptr, nullptr, nullptr); if (osStatus == noErr) { if (actualType == itemType && actualFormat == dataFormat) { return PAL_Pkcs7; } } dataFormat = kSecFormatPKCS12; actualFormat = dataFormat; itemType = kSecItemTypeAggregate; actualType = itemType; osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, nullptr, nullptr, nullptr); if (osStatus == errSecPassphraseRequired) { dataFormat = kSecFormatPKCS12; actualFormat = dataFormat; itemType = kSecItemTypeAggregate; actualType = itemType; SecItemImportExportKeyParameters importParams = {}; importParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; importParams.passphrase = CFSTR(""); osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, &importParams, nullptr, nullptr); CFRelease(importParams.passphrase); importParams.passphrase = nullptr; } if (osStatus == noErr || osStatus == errSecPkcs12VerifyFailure) { if (actualType == itemType && actualFormat == dataFormat) { return PAL_Pkcs12; } } dataFormat = kSecFormatX509Cert; actualFormat = dataFormat; itemType = kSecItemTypeCertificate; actualType = itemType; osStatus = SecItemImport(cfData, nullptr, &actualFormat, &actualType, 0, nullptr, nullptr, nullptr); if (osStatus == noErr) { if (actualType == itemType && actualFormat == dataFormat) { return PAL_Certificate; } } return PAL_X509Unknown; }
static int import_pem(URLContext *h, char *path, CFArrayRef *array) { AVIOContext *s = NULL; CFDataRef data = NULL; int64_t ret = 0; char *buf = NULL; SecExternalFormat format = kSecFormatPEMSequence; SecExternalFormat type = kSecItemTypeAggregate; CFStringRef pathStr = CFStringCreateWithCString(NULL, path, 0x08000100); if (!pathStr) { ret = AVERROR(ENOMEM); goto end; } if ((ret = ffio_open_whitelist(&s, path, AVIO_FLAG_READ, &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist)) < 0) goto end; if ((ret = avio_size(s)) < 0) goto end; if (ret == 0) { ret = AVERROR_INVALIDDATA; goto end; } if (!(buf = av_malloc(ret))) { ret = AVERROR(ENOMEM); goto end; } if ((ret = avio_read(s, buf, ret)) < 0) goto end; data = CFDataCreate(kCFAllocatorDefault, buf, ret); if (SecItemImport(data, pathStr, &format, &type, 0, NULL, NULL, array) != noErr || !array) { ret = AVERROR_UNKNOWN; goto end; } if (CFArrayGetCount(*array) == 0) { ret = AVERROR_INVALIDDATA; goto end; } end: av_free(buf); if (pathStr) CFRelease(pathStr); if (data) CFRelease(data); if (s) avio_close(s); return ret; }
static OSStatus AddKeyToKeychain(SecKeyRef privateKey, SecKeychainRef targetKeychain) { // This is quite similar to pal_seckey's ExportImportKey, but // a) is used to put something INTO a keychain, instead of to take it out. // b) Doesn't assume that the input should be CFRelease()d and overwritten. // c) Doesn't return/emit the imported key reference. // d) Works on private keys. SecExternalFormat dataFormat = kSecFormatWrappedPKCS8; CFDataRef exportData = nullptr; SecItemImportExportKeyParameters keyParams = {}; keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; keyParams.passphrase = CFSTR("ExportImportPassphrase"); OSStatus status = SecItemExport(privateKey, dataFormat, 0, &keyParams, &exportData); SecExternalFormat actualFormat = dataFormat; SecExternalItemType actualType = kSecItemTypePrivateKey; CFArrayRef outItems = nullptr; if (status == noErr) { status = SecItemImport(exportData, nullptr, &actualFormat, &actualType, 0, &keyParams, targetKeychain, &outItems); } if (exportData != nullptr) CFRelease(exportData); CFRelease(keyParams.passphrase); keyParams.passphrase = nullptr; if (outItems != nullptr) CFRelease(outItems); return status; }
static int32_t ReadX509(uint8_t* pbData, int32_t cbData, PAL_X509ContentType contentType, CFStringRef cfPfxPassphrase, SecKeychainRef keychain, bool exportable, SecCertificateRef* pCertOut, SecIdentityRef* pIdentityOut, CFArrayRef* pCollectionOut, int32_t* pOSStatus) { assert(pbData != nullptr); assert(cbData >= 0); assert((pCertOut == nullptr) == (pIdentityOut == nullptr)); assert((pCertOut == nullptr) != (pCollectionOut == nullptr)); SecExternalFormat dataFormat; SecExternalItemType itemType; int32_t ret = 0; CFArrayRef outItems = nullptr; CFMutableArrayRef keyAttributes = nullptr; SecKeychainRef importKeychain = nullptr; SecItemImportExportKeyParameters importParams = {}; importParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; if (contentType == PAL_Certificate) { dataFormat = kSecFormatX509Cert; itemType = kSecItemTypeCertificate; } else if (contentType == PAL_Pkcs7) { dataFormat = kSecFormatPKCS7; itemType = kSecItemTypeAggregate; } else if (contentType == PAL_Pkcs12) { dataFormat = kSecFormatPKCS12; itemType = kSecItemTypeAggregate; importParams.passphrase = cfPfxPassphrase; importKeychain = keychain; if (keychain == nullptr) { return kErrorBadInput; } // if keyAttributes is nullptr then it uses SENSITIVE | EXTRACTABLE // so if !exportable was requested, assert SENSITIVE. if (!exportable) { keyAttributes = CFArrayCreateMutable(nullptr, 9, &kCFTypeArrayCallBacks); if (keyAttributes == nullptr) { *pOSStatus = errSecAllocate; return 0; } int32_t sensitiveValue = CSSM_KEYATTR_SENSITIVE; CFNumberRef sensitive = CFNumberCreate(nullptr, kCFNumberSInt32Type, &sensitiveValue); if (sensitive == nullptr) { CFRelease(keyAttributes); *pOSStatus = errSecAllocate; return 0; } CFArrayAppendValue(keyAttributes, sensitive); CFRelease(sensitive); importParams.keyAttributes = keyAttributes; } } else { *pOSStatus = errSecUnknownFormat; return 0; } CFDataRef cfData = CFDataCreateWithBytesNoCopy(nullptr, pbData, cbData, kCFAllocatorNull); if (cfData == nullptr) { *pOSStatus = errSecAllocate; } if (*pOSStatus == noErr) { *pOSStatus = SecItemImport(cfData, nullptr, &dataFormat, &itemType, 0, &importParams, keychain, &outItems); } if (contentType == PAL_Pkcs12 && *pOSStatus == errSecPassphraseRequired && cfPfxPassphrase == nullptr) { if (outItems != nullptr) { CFRelease(outItems); outItems = nullptr; } // Try again with the empty string passphrase. importParams.passphrase = CFSTR(""); *pOSStatus = SecItemImport(cfData, nullptr, &dataFormat, &itemType, 0, &importParams, keychain, &outItems); CFRelease(importParams.passphrase); importParams.passphrase = nullptr; } if (*pOSStatus == noErr) { if (pCollectionOut != nullptr) { CFRetain(outItems); *pCollectionOut = outItems; ret = 1; } else { ret = ProcessCertificateTypeReturn(outItems, pCertOut, pIdentityOut); } } if (keyAttributes != nullptr) { CFRelease(keyAttributes); } if (outItems != nullptr) { // In the event this is returned via pCollectionOut it was already // CFRetain()ed, so always CFRelease here. CFRelease(outItems); } CFRelease(cfData); return ret; }
bool _mongoc_secure_transport_import_pem (const char *filename, const char *passphrase, CFArrayRef *items, SecExternalItemType *type) { SecExternalFormat format = kSecFormatPEMSequence; SecItemImportExportKeyParameters params; SecTransformRef sec_transform; CFReadStreamRef read_stream; CFDataRef dataref; CFErrorRef error; CFURLRef url; OSStatus res; if (!filename) { MONGOC_INFO ("%s", "No certificate provided"); return false; } params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; params.flags = 0; params.passphrase = NULL; params.alertTitle = NULL; params.alertPrompt = NULL; params.accessRef = NULL; params.keyUsage = NULL; params.keyAttributes = NULL; if (passphrase) { params.passphrase = CFStringCreateWithCString (kCFAllocatorDefault, passphrase, kCFStringEncodingUTF8); } url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault, (const UInt8 *)filename, strlen (filename), false); read_stream = CFReadStreamCreateWithFile (kCFAllocatorDefault, url); sec_transform = SecTransformCreateReadTransformWithReadStream (read_stream); dataref = SecTransformExecute (sec_transform, &error); if (error) { CFStringRef str = CFErrorCopyDescription (error); MONGOC_ERROR ("Failed importing PEM '%s': %s", filename, CFStringGetCStringPtr (str, CFStringGetFastestEncoding(str))); CFRelease (str); CFRelease (sec_transform); CFRelease (read_stream); CFRelease (url); if (passphrase) { CFRelease (params.passphrase); } return false; } res = SecItemImport (dataref, CFSTR(".pem"), &format, type, 0, ¶ms, NULL, items); CFRelease (dataref); CFRelease (sec_transform); CFRelease (read_stream); CFRelease (url); if (passphrase) { CFRelease (params.passphrase); } if (res) { MONGOC_ERROR ("Failed importing PEM '%s' (code: %d)", filename, res); return false; } return true; }
Boolean APSetKey(CFStringRef key) { hash = CFSTR(""); blacklist = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); CFMutableStringRef mutableKey = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, key); CFStringRef preparedKey = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, key); CFLocaleRef currentLocale = CFLocaleCopyCurrent(); CFStringLowercase(mutableKey, currentLocale); CFRelease(currentLocale); if (CFStringHasPrefix(mutableKey, CFSTR("0x")) && CFStringGetLength(mutableKey) > 2) { CFStringDelete(mutableKey, CFRangeMake(0, 2)); } if (CFStringGetLength(mutableKey) == 1024/8*2) { CFRelease(preparedKey); preparedKey = APPEMKeyCreateFromHexKey(mutableKey); } CFRelease(mutableKey); SecItemImportExportKeyParameters params = {0}; params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; params.flags = kSecKeyNoAccessControl; SecExternalItemType itemType = kSecItemTypePublicKey; SecExternalFormat externalFormat = kSecFormatPEMSequence; CFArrayRef tempArray = NULL; OSStatus oserr = noErr; // Set the key as extractable. Looking through the source code in SecImportExportUtils.cpp // it looks like this isn't handled, yet it seems to be documented to me. One day the code // may catch up, so I'm leaving this here to show the intention. CFNumberRef attributeFlags[1]; uint32 flag0value = CSSM_KEYATTR_EXTRACTABLE; CFNumberRef flag0 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &flag0value); attributeFlags[0] = flag0; CFArrayRef keyAttributes = CFArrayCreate(kCFAllocatorDefault, (const void **)attributeFlags, 1, &kCFTypeArrayCallBacks); CFRelease(flag0); params.keyAttributes = keyAttributes; CFDataRef keyData = CFStringCreateExternalRepresentation(kCFAllocatorDefault, preparedKey, kCFStringEncodingUTF8, 0); CFRelease(preparedKey); oserr = SecItemImport(keyData, NULL, &externalFormat, &itemType, 0, ¶ms, NULL, &tempArray); CFRelease(keyAttributes); CFRelease(keyData); if (oserr != noErr) { CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Unable to import key. Error %d"), oserr); CFShow(errorString); CFRelease(errorString); return FALSE; } publicKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(tempArray, 0); CFRetain(publicKeyRef); CFRelease(tempArray); return TRUE; }