X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/OSX/libsecurity_keychain/lib/SecCertificate.cpp?ds=sidebyside diff --git a/OSX/libsecurity_keychain/lib/SecCertificate.cpp b/OSX/libsecurity_keychain/lib/SecCertificate.cpp new file mode 100644 index 00000000..9950aa33 --- /dev/null +++ b/OSX/libsecurity_keychain/lib/SecCertificate.cpp @@ -0,0 +1,1538 @@ +/* + * Copyright (c) 2002-2015 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@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "SecBridge.h" + +// %%% used by SecCertificate{Copy,Set}Preference +#include +#include +#include +#include +#include +#include +#include +#include "CertificateValues.h" +#include "SecCertificateP.h" +#include "SecCertificatePrivP.h" + +#include "AppleBaselineEscrowCertificates.h" + + +SecCertificateRef SecCertificateCreateItemImplInstance(SecCertificateRef certificate); +OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle); +extern CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage); + +#define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v); + +SEC_CONST_DECL (kSecCertificateProductionEscrowKey, "ProductionEscrowKey"); +SEC_CONST_DECL (kSecCertificateProductionPCSEscrowKey, "ProductionPCSEscrowKey"); +SEC_CONST_DECL (kSecCertificateEscrowFileName, "AppleESCertificates"); + + +using namespace CssmClient; + +#if !SECTRUST_OSX +CFTypeID +SecCertificateGetTypeID(void) +{ + BEGIN_SECAPI + + return gTypes().Certificate.typeID; + + END_SECAPI1(_kCFRuntimeNotATypeID) +} +#endif + +/* convert a new-world SecCertificateRef to an old-world ItemImpl instance */ +SecCertificateRef +SecCertificateCreateItemImplInstance(SecCertificateRef certificate) +{ +#if !SECTRUST_OSX + return (SecCertificateRef)(certificate ? CFRetain(certificate) : NULL); +#else + if (!certificate) { + return NULL; + } + SecCertificateRef implCertRef = (SecCertificateRef) SecCertificateCopyKeychainItem(certificate); + if (implCertRef) { + return implCertRef; + } + CFDataRef data = SecCertificateCopyData(certificate); + if (!data) { + return NULL; + } + try { + CSSM_DATA cssmCertData; + cssmCertData.Length = (data) ? (CSSM_SIZE)CFDataGetLength(data) : 0; + cssmCertData.Data = (data) ? (uint8 *)CFDataGetBytePtr(data) : NULL; + + SecPointer certificatePtr(new Certificate(cssmCertData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER)); + implCertRef = certificatePtr->handle(); + } + catch (...) {} + CFRelease(data); + return implCertRef; +#endif +} + +/* convert an old-world ItemImpl instance to a new-world SecCertificateRef */ +SecCertificateRef +SecCertificateCreateFromItemImplInstance(SecCertificateRef certificate) +{ +#if !SECTRUST_OSX + return (SecCertificateRef)(certificate ? CFRetain(certificate) : NULL); +#else + if (!certificate) { + return NULL; + } + SecCertificateRef result = NULL; + CFDataRef data = NULL; + try { + CssmData certData = Certificate::required(certificate)->data(); + if (certData.Data && certData.Length) { + data = CFDataCreate(NULL, certData.Data, certData.Length); + } + if (!data) { + if (certData.Data && !certData.Length) { + /* zero-length certs can exist, so don't bother logging this */ + } + else { + syslog(LOG_ERR, "WARNING: SecKeychainSearchCopyNext failed to retrieve certificate data (length=%ld, data=0x%lX)", + (long)certData.Length, (uintptr_t)certData.Data); + } + return NULL; + } + } + catch (...) {} + + result = SecCertificateCreateWithKeychainItem(NULL, data, certificate); + if (data) + CFRelease(data); + return result; +#endif +} + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateCreateFromData(const CSSM_DATA *data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding, SecCertificateRef *certificate) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + + SecPointer certificatePtr(new Certificate(Required(data), type, encoding)); + Required(certificate) = certificatePtr->handle(); + + END_SECAPI +#else + /* bridge to support old functionality */ + if (!data || !data->Data || !data->Length || !certificate) { + return errSecParam; + } + SecCertificateRef certRef = NULL; + CFDataRef dataRef = CFDataCreate(NULL, data->Data, data->Length); + if (dataRef) { + certRef = SecCertificateCreateWithData(NULL, dataRef); + CFRelease(dataRef); + } + *certificate = certRef; + return (certRef) ? errSecSuccess : errSecUnknownFormat; +#endif +} + +#if !SECTRUST_OSX +/* new in 10.6 */ +SecCertificateRef +SecCertificateCreateWithData(CFAllocatorRef allocator, CFDataRef data) +{ + SecCertificateRef certificate = NULL; + OSStatus __secapiresult; + try { + CSSM_DATA cssmCertData; + cssmCertData.Length = (data) ? (CSSM_SIZE)CFDataGetLength(data) : 0; + cssmCertData.Data = (data) ? (uint8 *)CFDataGetBytePtr(data) : NULL; + + //NOTE: there isn't yet a Certificate constructor which accepts a CFAllocatorRef + SecPointer certificatePtr(new Certificate(cssmCertData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER)); + certificate = certificatePtr->handle(); + + __secapiresult=errSecSuccess; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return certificate; +} +#endif + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA) */ +OSStatus +SecCertificateAddToKeychain(SecCertificateRef certificate, SecKeychainRef keychain) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Item item(Certificate::required(__itemImplRef)); + Keychain::optional(keychain)->add(item); + + END_SECCERTAPI +} + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateGetData(SecCertificateRef certificate, CSSM_DATA_PTR data) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(data) = Certificate::required(__itemImplRef)->data(); + + END_SECCERTAPI +} + +#if !SECTRUST_OSX +/* new in 10.6 */ +CFDataRef +SecCertificateCopyData(SecCertificateRef certificate) +{ + CFDataRef data = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + CssmData output = Certificate::required(certificate)->data(); + CFIndex length = (CFIndex)output.length(); + const UInt8 *bytes = (const UInt8 *)output.data(); + if (length && bytes) { + data = CFDataCreate(NULL, bytes, length); + } + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return data; +} +#endif + +#if !SECTRUST_OSX +CFDataRef +SecCertificateGetSHA1Digest(SecCertificateRef certificate) +{ + CFDataRef data = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + data = Certificate::required(certificate)->sha1Hash(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return data; +} +#endif + +#if !SECTRUST_OSX +CFDataRef +SecCertificateCopyPublicKeySHA1Digest(SecCertificateRef certificate) +{ + CFDataRef data = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + CssmData output = Certificate::required(certificate)->publicKeyHash(); + CFIndex length = (CFIndex)output.length(); + const UInt8 *bytes = (const UInt8 *)output.data(); + if (length && bytes) { + data = CFDataCreate(NULL, bytes, length); + } + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return data; +} +#endif + +#if !SECTRUST_OSX +CFArrayRef +SecCertificateCopyDNSNames(SecCertificateRef certificate) +{ + CFArrayRef names = NULL; + OSStatus __secapiresult = errSecSuccess; + try { + names = Certificate::required(certificate)->copyDNSNames(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return names; +} +#endif + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateGetType(SecCertificateRef certificate, CSSM_CERT_TYPE *certificateType) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(certificateType) = Certificate::required(__itemImplRef)->type(); + + END_SECCERTAPI +} + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateGetSubject(SecCertificateRef certificate, const CSSM_X509_NAME **subject) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(subject) = Certificate::required(__itemImplRef)->subjectName(); + + END_SECCERTAPI +} + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateGetIssuer(SecCertificateRef certificate, const CSSM_X509_NAME **issuer) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(issuer) = Certificate::required(__itemImplRef)->issuerName(); + + END_SECCERTAPI +} + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateGetCLHandle(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) +{ +#if !SECTRUST_OSX + BEGIN_SECAPI + + Required(clHandle) = Certificate::required(certificate)->clHandle(); + + END_SECAPI +#else +#if 0 + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(clHandle) = Certificate::required(__itemImplRef)->clHandle(); + + END_SECCERTAPI +#endif + /* bridge code to support deprecated functionality */ + OSStatus __secapiresult=errSecSuccess; + bool kcItem=true; + SecCertificateRef __itemImplRef=(SecCertificateRef)SecCertificateCopyKeychainItem(certificate); + if (!__itemImplRef) { __itemImplRef=SecCertificateCreateItemImplInstance(certificate); kcItem=false; } + try { + Required(clHandle) = Certificate::required(__itemImplRef)->clHandle(); + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + if (__itemImplRef) { + if (!kcItem) { + /* we can't release the temporary certificate, or the CL handle becomes invalid. + * for now, just stick the temporary certificate into an array. + * TBD: use a dictionary, indexed by hash of certificate. */ + static CFMutableArrayRef sLegacyCertArray = NULL; + if (!sLegacyCertArray) { + sLegacyCertArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!sLegacyCertArray) { + return errSecAllocate; + } + } + CFArrayAppendValue(sLegacyCertArray, __itemImplRef); +#ifndef NDEBUG + syslog(LOG_ERR, "WARNING: SecCertificateGetCLHandle called on certificate which is not in a keychain."); +#endif + } + CFRelease(__itemImplRef); + } + return __secapiresult; + +#endif +} + +/* private function; assumes input is old-style ItemImpl certificate reference, + and does not release that certificate reference! + */ +OSStatus +SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle) +{ + BEGIN_SECAPI + + Required(clHandle) = Certificate::required(certificate)->clHandle(); + + END_SECAPI +} + + +/* + * Private API to infer a display name for a SecCertificateRef which + * may or may not be in a keychain. + * + * OS X only + */ +OSStatus +SecCertificateInferLabel(SecCertificateRef certificate, CFStringRef *label) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Certificate::required(__itemImplRef)->inferLabel(false, &Required(label)); + + END_SECCERTAPI +} + +/* OS X only (note: iOS version has different arguments and return value) */ +OSStatus +SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef *key) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(key) = Certificate::required(__itemImplRef)->publicKey()->handle(); + + END_SECCERTAPI +} + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateGetAlgorithmID(SecCertificateRef certificate, const CSSM_X509_ALGORITHM_IDENTIFIER **algid) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(algid) = Certificate::required(__itemImplRef)->algorithmID(); + + END_SECCERTAPI +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */ +OSStatus +SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef *commonName) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(commonName) = Certificate::required(__itemImplRef)->commonName(); + + END_SECCERTAPI +} + +#if !SECTRUST_OSX +/* new in 10.6 */ +CFStringRef +SecCertificateCopySubjectSummary(SecCertificateRef certificate) +{ + CFStringRef summary = NULL; + OSStatus __secapiresult; + try { + Certificate::required(certificate)->inferLabel(false, &summary); + + __secapiresult=errSecSuccess; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return summary; +} +#endif + +#if !SECTRUST_OSX +CFStringRef +SecCertificateCopyIssuerSummary(SecCertificateRef certificate) +{ + CFStringRef issuerStr = NULL; + SecCertificateRefP certP = NULL; + CFDataRef certData = SecCertificateCopyData(certificate); + if (certData) { + certP = SecCertificateCreateWithDataP(NULL, certData); + CFRelease(certData); + } + if (certP) { + issuerStr = SecCertificateCopyIssuerSummaryP(certP); + CFRelease(certP); + } + return issuerStr; +} +#endif + +/* OS X only */ +OSStatus +SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component, CFStringRef *result) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(result) = Certificate::required(__itemImplRef)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, component); + + END_SECCERTAPI +} + +/* OS X only; deprecated SPI */ +OSStatus +SecCertificateGetCommonName(SecCertificateRef certificate, CFStringRef *commonName) +{ + // deprecated SPI signature; replaced by SecCertificateCopyCommonName + return SecCertificateCopyCommonName(certificate, commonName); +} + +/* OS X only; deprecated SPI */ +OSStatus +SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailAddress) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(emailAddress) = Certificate::required(__itemImplRef)->copyFirstEmailAddress(); + + END_SECCERTAPI +} + +/* OS X only */ +OSStatus +SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef *emailAddresses) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(emailAddresses) = Certificate::required(__itemImplRef)->copyEmailAddresses(); + + END_SECCERTAPI +} + +/* Return a zero terminated list of CSSM_DATA_PTR's with the values of the field specified by field. + * Caller must call releaseFieldValues to free the storage allocated by this call. + * + * OS X only + */ +OSStatus +SecCertificateCopyFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR **fieldValues) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(fieldValues) = Certificate::required(__itemImplRef)->copyFieldValues(Required(field)); + + END_SECCERTAPI +} + +/* OS X only */ +OSStatus +SecCertificateReleaseFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValues) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Certificate::required(__itemImplRef)->releaseFieldValues(Required(field), fieldValues); + + END_SECCERTAPI +} + +/* OS X only */ +OSStatus +SecCertificateCopyFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValue) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Required(fieldValue) = Certificate::required(__itemImplRef)->copyFirstFieldValue(Required(field)); + + END_SECCERTAPI +} + +/* OS X only */ +OSStatus +SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR fieldValue) +{ + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + Certificate::required(__itemImplRef)->releaseFieldValue(Required(field), fieldValue); + + END_SECCERTAPI +} + +/* OS X only */ +OSStatus +SecCertificateFindByIssuerAndSN(CFTypeRef keychainOrArray,const CSSM_DATA *issuer, + const CSSM_DATA *serialNumber, SecCertificateRef *certificate) +{ + BEGIN_SECAPI + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + Required(certificate) = Certificate::findByIssuerAndSN(keychains, CssmData::required(issuer), CssmData::required(serialNumber))->handle(); + +#if SECTRUST_OSX + // convert ItemImpl-based SecCertificateRef to new-world version before returning + CssmData certData = Certificate::required(*certificate)->data(); + CFRef cfData(CFDataCreate(NULL, certData.Data, certData.Length)); + SecCertificateRef tmpRef = *certificate; + *certificate = SecCertificateCreateWithData(NULL, cfData); + CFRelease(tmpRef); +#endif + + END_SECAPI +} + +/* OS X only */ +OSStatus +SecCertificateFindBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, + SecCertificateRef *certificate) +{ + BEGIN_SECAPI + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + Required(certificate) = Certificate::findBySubjectKeyID(keychains, CssmData::required(subjectKeyID))->handle(); + +#if SECTRUST_OSX + // convert ItemImpl-based SecCertificateRef to new-world version before returning + CssmData certData = Certificate::required(*certificate)->data(); + CFRef cfData(CFDataCreate(NULL, certData.Data, certData.Length)); + SecCertificateRef tmpRef = *certificate; + *certificate = SecCertificateCreateWithData(NULL, cfData); + CFRelease(tmpRef); +#endif + + END_SECAPI +} + +/* OS X only */ +OSStatus +SecCertificateFindByEmail(CFTypeRef keychainOrArray, const char *emailAddress, SecCertificateRef *certificate) +{ + BEGIN_SECAPI + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + Required(certificate) = Certificate::findByEmail(keychains, emailAddress)->handle(); + +#if SECTRUST_OSX + // convert ItemImpl-based SecCertificateRef to new-world version before returning + CssmData certData = Certificate::required(*certificate)->data(); + CFRef cfData(CFDataCreate(NULL, certData.Data, certData.Length)); + SecCertificateRef tmpRef = *certificate; + *certificate = SecCertificateCreateWithData(NULL, cfData); + CFRelease(tmpRef); +#endif + + END_SECAPI +} + +/* OS X only */ +OSStatus +SecKeychainSearchCreateForCertificateByIssuerAndSN(CFTypeRef keychainOrArray, const CSSM_DATA *issuer, + const CSSM_DATA *serialNumber, SecKeychainSearchRef *searchRef) +{ + BEGIN_SECAPI + + Required(searchRef); + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + KCCursor cursor(Certificate::cursorForIssuerAndSN(keychains, CssmData::required(issuer), CssmData::required(serialNumber))); + *searchRef = cursor->handle(); + + END_SECAPI +} + +/* OS X only */ +OSStatus +SecKeychainSearchCreateForCertificateByIssuerAndSN_CF(CFTypeRef keychainOrArray, CFDataRef issuer, + CFDataRef serialNumber, SecKeychainSearchRef *searchRef) +{ + BEGIN_SECAPI + + Required(searchRef); + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + Required(issuer); + Required(serialNumber); + KCCursor cursor(Certificate::cursorForIssuerAndSN_CF(keychains, issuer, serialNumber)); + *searchRef = cursor->handle(); + + END_SECAPI +} + +/* OS X only */ +OSStatus +SecKeychainSearchCreateForCertificateBySubjectKeyID(CFTypeRef keychainOrArray, const CSSM_DATA *subjectKeyID, + SecKeychainSearchRef *searchRef) +{ + BEGIN_SECAPI + + Required(searchRef); + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + KCCursor cursor(Certificate::cursorForSubjectKeyID(keychains, CssmData::required(subjectKeyID))); + *searchRef = cursor->handle(); + + END_SECAPI +} + +/* OS X only */ +OSStatus +SecKeychainSearchCreateForCertificateByEmail(CFTypeRef keychainOrArray, const char *emailAddress, + SecKeychainSearchRef *searchRef) +{ + BEGIN_SECAPI + + Required(searchRef); + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + KCCursor cursor(Certificate::cursorForEmail(keychains, emailAddress)); + *searchRef = cursor->handle(); + + END_SECAPI +} + +/* OS X only */ +CSSM_RETURN +SecDigestGetData (CSSM_ALGORITHMS alg, CSSM_DATA* digest, const CSSM_DATA* data) +{ + BEGIN_SECAPI + // sanity checking + if (!digest || !digest->Data || !digest->Length || !data || !data->Data || !data->Length) + return errSecParam; + + CSP csp(gGuidAppleCSP); + Digest context(csp, alg); + CssmData input(data->Data, data->Length); + CssmData output(digest->Data, digest->Length); + + context.digest(input, output); + digest->Length = output.length(); + + return CSSM_OK; + END_SECAPI1(1); +} + +#if !SECTRUST_OSX +/* determine whether a cert is self-signed */ +OSStatus SecCertificateIsSelfSigned( + SecCertificateRef certificate, + Boolean *isSelfSigned) /* RETURNED */ +{ + BEGIN_SECAPI + + *isSelfSigned = Certificate::required(certificate)->isSelfSigned(); + + END_SECAPI +} +#endif + +/* OS X only: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER */ +OSStatus +SecCertificateCopyPreference( + CFStringRef name, + CSSM_KEYUSE keyUsage, + SecCertificateRef *certificate) +{ + BEGIN_SECAPI + + Required(name); + Required(certificate); + StorageManager::KeychainList keychains; + globals().storageManager.getSearchList(keychains); + KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); + + char idUTF8[MAXPATHLEN]; + if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8)) + idUTF8[0] = (char)'\0'; + CssmData service(const_cast(idUTF8), strlen(idUTF8)); + FourCharCode itemType = 'cprf'; + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType); + if (keyUsage) + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); + + Item prefItem; + if (!cursor->next(prefItem)) + MacOSError::throwMe(errSecItemNotFound); + + // get persistent certificate reference + SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } }; + SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs }; + prefItem->getContent(NULL, &itemAttrList, NULL, NULL); + + // find certificate, given persistent reference data + CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull); + SecKeychainItemRef certItemRef = nil; + OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); //%%% need to make this a method of ItemImpl + prefItem->freeContent(&itemAttrList, NULL); + if (pItemRef) + CFRelease(pItemRef); + if (status) + return status; + + *certificate = (SecCertificateRef)certItemRef; + +#if SECTRUST_OSX + // convert ItemImpl-based SecCertificateRef to new-world version before returning + CssmData certData = Certificate::required(*certificate)->data(); + CFRef cfData(CFDataCreate(NULL, certData.Data, certData.Length)); + SecCertificateRef tmpRef = *certificate; + *certificate = SecCertificateCreateWithData(NULL, cfData); + CFRelease(tmpRef); +#endif + + END_SECAPI +} + +/* OS X only */ +SecCertificateRef +SecCertificateCopyPreferred( + CFStringRef name, + CFArrayRef keyUsage) +{ + // This function will look for a matching preference in the following order: + // - matches the name and the supplied key use + // - matches the name and the special 'ANY' key use + // - matches the name with no key usage constraint + + SecCertificateRef certRef = NULL; + CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage); + OSStatus status = SecCertificateCopyPreference(name, keyUse, &certRef); + if (status != errSecSuccess && keyUse != CSSM_KEYUSE_ANY) + status = SecCertificateCopyPreference(name, CSSM_KEYUSE_ANY, &certRef); + if (status != errSecSuccess && keyUse != 0) + status = SecCertificateCopyPreference(name, 0, &certRef); + + return certRef; +} + +/* OS X only; not exported */ +static OSStatus +SecCertificateFindPreferenceItemWithNameAndKeyUsage( + CFTypeRef keychainOrArray, + CFStringRef name, + int32_t keyUsage, + SecKeychainItemRef *itemRef) +{ + BEGIN_SECAPI + + StorageManager::KeychainList keychains; + globals().storageManager.optionalSearchList(keychainOrArray, keychains); + KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); + + char idUTF8[MAXPATHLEN]; + idUTF8[0] = (char)'\0'; + if (name) + { + if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8)) + idUTF8[0] = (char)'\0'; + } + size_t idUTF8Len = strlen(idUTF8); + if (!idUTF8Len) + MacOSError::throwMe(errSecParam); + + CssmData service(const_cast(idUTF8), idUTF8Len); + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'cprf'); + if (keyUsage) + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); + + Item item; + if (!cursor->next(item)) + MacOSError::throwMe(errSecItemNotFound); + + if (itemRef) + *itemRef=item->handle(); + + END_SECAPI +} + +/* OS X only; not exported */ +static +OSStatus SecCertificateDeletePreferenceItemWithNameAndKeyUsage( + CFTypeRef keychainOrArray, + CFStringRef name, + int32_t keyUsage) +{ + // when a specific key usage is passed, we'll only match & delete that pref; + // when a key usage of 0 is passed, all matching prefs should be deleted. + // maxUsages represents the most matches there could theoretically be, so + // cut things off at that point if we're still finding items (if they can't + // be deleted for some reason, we'd never break out of the loop.) + + OSStatus status; + SecKeychainItemRef item = NULL; + int count = 0, maxUsages = 12; + while (++count <= maxUsages && + (status = SecCertificateFindPreferenceItemWithNameAndKeyUsage(keychainOrArray, name, keyUsage, &item)) == errSecSuccess) { + status = SecKeychainItemDelete(item); + CFRelease(item); + item = NULL; + } + + // it's not an error if the item isn't found + return (status == errSecItemNotFound) ? errSecSuccess : status; +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA) */ +OSStatus SecCertificateSetPreference( + SecCertificateRef certificate, + CFStringRef name, + CSSM_KEYUSE keyUsage, + CFDateRef date) +{ + if (!name) { + return errSecParam; + } + if (!certificate) { + // treat NULL certificate as a request to clear the preference + // (note: if keyUsage is 0, this clears all key usage prefs for name) + return SecCertificateDeletePreferenceItemWithNameAndKeyUsage(NULL, name, keyUsage); + } + + // This macro converts a new-style SecCertificateRef to an old-style ItemImpl + BEGIN_SECCERTAPI + + // determine the account attribute + // + // This attribute must be synthesized from certificate label + pref item type + key usage, + // as only the account and service attributes can make a generic keychain item unique. + // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that + // we can save a certificate preference if an identity preference already exists for the + // given service name, and vice-versa. + // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string. + // + CFStringRef labelStr = nil; + Certificate::required(__itemImplRef)->inferLabel(false, &labelStr); + if (!labelStr) { + MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed" + } + CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1; + const char *templateStr = "%s [key usage 0x%X]"; + const int keyUsageMaxStrLen = 8; + accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen; + char accountUTF8[accountUTF8Len]; + if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8)) + accountUTF8[0] = (char)'\0'; + if (keyUsage) + snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage); + CssmData account(const_cast(accountUTF8), strlen(accountUTF8)); + CFRelease(labelStr); + + // service attribute (name provided by the caller) + CFIndex serviceUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(name), kCFStringEncodingUTF8) + 1;; + char serviceUTF8[serviceUTF8Len]; + if (!CFStringGetCString(name, serviceUTF8, serviceUTF8Len-1, kCFStringEncodingUTF8)) + serviceUTF8[0] = (char)'\0'; + CssmData service(const_cast(serviceUTF8), strlen(serviceUTF8)); + + // look for existing preference item, in case this is an update + StorageManager::KeychainList keychains; + globals().storageManager.getSearchList(keychains); + KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); + FourCharCode itemType = 'cprf'; + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType); + if (keyUsage) + cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); + if (date) + ; // %%%TBI + + Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false); + bool add = (!cursor->next(item)); + // at this point, we either have a new item to add or an existing item to update + + // set item attribute values + item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service); + item->setAttribute(Schema::attributeInfo(kSecTypeItemAttr), itemType); + item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account); + item->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); + item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service); + + // date + if (date) + ; // %%%TBI + + // generic attribute (store persistent certificate reference) + CFDataRef pItemRef = nil; + Certificate::required(__itemImplRef)->copyPersistentReference(pItemRef); + if (!pItemRef) { + MacOSError::throwMe(errSecInvalidItemRef); + } + const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef); + CFIndex dataLen = CFDataGetLength(pItemRef); + CssmData pref(const_cast(reinterpret_cast(dataPtr)), dataLen); + item->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref); + CFRelease(pItemRef); + + if (add) { + Keychain keychain = nil; + try { + keychain = globals().storageManager.defaultKeychain(); + if (!keychain->exists()) + MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time. + } + catch(...) { + keychain = globals().storageManager.defaultKeychainUI(item); + } + + try { + keychain->add(item); + } + catch (const MacOSError &err) { + if (err.osStatus() != errSecDuplicateItem) + throw; // if item already exists, fall through to update + } + } + item->update(); + + END_SECCERTAPI +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +OSStatus SecCertificateSetPreferred( + SecCertificateRef certificate, + CFStringRef name, + CFArrayRef keyUsage) +{ + CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage); + return SecCertificateSetPreference(certificate, name, keyUse, NULL); +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +CFDictionaryRef SecCertificateCopyValues(SecCertificateRef certificate, CFArrayRef keys, CFErrorRef *error) +{ + CFDictionaryRef result = NULL; + OSStatus __secapiresult; + try + { + CertificateValues cv(certificate); + result = cv.copyFieldValues(keys,error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +CFStringRef SecCertificateCopyLongDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error) +{ + return SecCertificateCopyShortDescription(alloc, certificate, error); +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +CFStringRef SecCertificateCopyShortDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error) +{ + CFStringRef result = NULL; + OSStatus __secapiresult = SecCertificateInferLabel(certificate, &result); + if (error!=NULL && __secapiresult!=errSecSuccess) + { + *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, + __secapiresult ? __secapiresult : CSSM_ERRCODE_INTERNAL_ERROR, NULL); + } + return result; +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error) +{ + CFDataRef result = NULL; + OSStatus __secapiresult; + try + { + CertificateValues cv(certificate); + result = cv.copySerialNumber(error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +CFDataRef SecCertificateCopyNormalizedIssuerContent(SecCertificateRef certificate, CFErrorRef *error) +{ + CFDataRef result = NULL; + OSStatus __secapiresult; + try + { + CertificateValues cv(certificate); + result = cv.copyNormalizedIssuerContent(error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} + +/* OS X only: __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA) */ +CFDataRef SecCertificateCopyNormalizedSubjectContent(SecCertificateRef certificate, CFErrorRef *error) +{ + CFDataRef result = NULL; + OSStatus __secapiresult; + try + { + CertificateValues cv(certificate); + result = cv.copyNormalizedSubjectContent(error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} + +#if !SECTRUST_OSX +CFDataRef SecCertificateCopyIssuerSequence(SecCertificateRef certificate) +{ + CFDataRef result = NULL; + OSStatus __secapiresult; + try + { + CertificateValues cv(certificate); + result = cv.copyIssuerSequence(NULL); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} +#endif + +#if !SECTRUST_OSX +CFDataRef SecCertificateCopySubjectSequence(SecCertificateRef certificate) +{ + CFDataRef result = NULL; + OSStatus __secapiresult; + try + { + CertificateValues cv(certificate); + result = cv.copySubjectSequence(NULL); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} +#endif + +#if !SECTRUST_OSX +bool SecCertificateIsValid(SecCertificateRef certificate, CFAbsoluteTime verifyTime) +{ + bool result = NULL; + OSStatus __secapiresult; + try + { + CFErrorRef error = NULL; + CertificateValues cv(certificate); + result = cv.isValid(verifyTime, &error); + if (error) CFRelease(error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} +#endif + +/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA) */ +bool SecCertificateIsValidX(SecCertificateRef certificate, CFAbsoluteTime verifyTime) +{ + /* + * deprecated function name + */ + return SecCertificateIsValid(certificate, verifyTime); +} + +#if !SECTRUST_OSX +CFAbsoluteTime SecCertificateNotValidBefore(SecCertificateRef certificate) +{ + CFAbsoluteTime result = 0; + OSStatus __secapiresult; + try + { + CFErrorRef error = NULL; + CertificateValues cv(certificate); + result = cv.notValidBefore(&error); + if (error) CFRelease(error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} +#endif + +#if !SECTRUST_OSX +CFAbsoluteTime SecCertificateNotValidAfter(SecCertificateRef certificate) +{ + CFAbsoluteTime result = 0; + OSStatus __secapiresult; + try + { + CFErrorRef error = NULL; + CertificateValues cv(certificate); + result = cv.notValidAfter(&error); + if (error) CFRelease(error); + __secapiresult=0; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return result; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.8 */ +SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator, + const UInt8 *bytes, CFIndex length) +{ + SecCertificateRef certificate = NULL; + OSStatus __secapiresult; + try { + CSSM_DATA cssmCertData = { (CSSM_SIZE)length, (uint8 *)bytes }; + + //NOTE: there isn't yet a Certificate constructor which accepts a CFAllocatorRef + SecPointer certificatePtr(new Certificate(cssmCertData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER)); + certificate = certificatePtr->handle(); + + __secapiresult=errSecSuccess; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return certificate; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.8 */ +CFIndex SecCertificateGetLength(SecCertificateRef certificate) +{ + CFIndex length = 0; + OSStatus __secapiresult; + try { + CssmData output = Certificate::required(certificate)->data(); + length = (CFIndex)output.length(); + __secapiresult=errSecSuccess; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return length; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.8 */ +const UInt8 *SecCertificateGetBytePtr(SecCertificateRef certificate) +{ + const UInt8 *bytes = NULL; + OSStatus __secapiresult; + try { + CssmData output = Certificate::required(certificate)->data(); + bytes = (const UInt8 *)output.data(); + __secapiresult=errSecSuccess; + } + catch (const MacOSError &err) { __secapiresult=err.osStatus(); } + catch (const CommonError &err) { __secapiresult=SecKeychainErrFromOSStatus(err.osStatus()); } + catch (const std::bad_alloc &) { __secapiresult=errSecAllocate; } + catch (...) { __secapiresult=errSecInternalComponent; } + return bytes; +} +#endif + +#if !SECTRUST_OSX +/* not exported */ +static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef *error) +{ + // Return array of CFDataRef certificates. + CFArrayRef result = NULL; + int iCnt; + int numRoots = 0; + + // Get the hard coded set of production roots + // static struct RootRecord* kProductionEscrowRoots[] = {&kOldEscrowRootRecord, &kProductionEscrowRootRecord}; + + struct RootRecord** pEscrowRoots = NULL; + switch (escrowRootType) { + case kSecCertificateBaselineEscrowRoot: + numRoots = kNumberOfBaseLineEscrowRoots; + pEscrowRoots = kBaseLineEscrowRoots; + break; + case kSecCertificateProductionEscrowRoot: + numRoots = kNumberOfBaseLineEscrowRoots; //%%% currently, production == baseline on OS X + pEscrowRoots = kBaseLineEscrowRoots; + break; + case kSecCertificateBaselinePCSEscrowRoot: + numRoots = kNumberOfBaseLinePCSEscrowRoots; + pEscrowRoots = kBaseLinePCSEscrowRoots; + break; + case kSecCertificateProductionPCSEscrowRoot: + numRoots = kNumberOfBaseLinePCSEscrowRoots; //%%% currently, production == baseline on OS X + pEscrowRoots = kBaseLinePCSEscrowRoots; + break; + default: + break; + } + + CFDataRef productionCerts[numRoots]; + struct RootRecord* pRootRecord = NULL; + + for (iCnt = 0; pEscrowRoots != NULL && iCnt < numRoots; iCnt++) + { + pRootRecord = pEscrowRoots[iCnt]; + if (NULL != pRootRecord && pRootRecord->_length > 0 && NULL != pRootRecord->_bytes) + { + productionCerts[iCnt] = CFDataCreate(kCFAllocatorDefault, pRootRecord->_bytes, pRootRecord->_length); + } + } + result = CFArrayCreate(kCFAllocatorDefault, (const void **)productionCerts, numRoots, &kCFTypeArrayCallBacks); + for (iCnt = 0; iCnt < numRoots; iCnt++) + { + if (NULL != productionCerts[iCnt]) + { + CFRelease(productionCerts[iCnt]); + } + } + + return result; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.9 */ +CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType) +{ + CFArrayRef result = NULL; + int iCnt; + int numRoots = 0; + CFDataRef certData = NULL; + + // The request is for the base line certificates. + // Use the hard coded data to generate the return array + if (kSecCertificateBaselineEscrowRoot == escrowRootType) + { + // Get the hard coded set of roots + numRoots = kNumberOfBaseLineEscrowRoots; + SecCertificateRef baseLineCerts[numRoots]; + struct RootRecord* pRootRecord = NULL; + + for (iCnt = 0; iCnt < numRoots; iCnt++) + { + pRootRecord = kBaseLineEscrowRoots[iCnt]; + if (NULL != pRootRecord && pRootRecord->_length > 0 && NULL != pRootRecord->_bytes) + { + certData = CFDataCreate(kCFAllocatorDefault, pRootRecord->_bytes, pRootRecord->_length); + if (NULL != certData) + { + baseLineCerts[iCnt] = SecCertificateCreateWithData(kCFAllocatorDefault, certData); + CFRelease(certData); + } + } + } + result = CFArrayCreate(kCFAllocatorDefault, (const void **)baseLineCerts, numRoots, &kCFTypeArrayCallBacks); + for (iCnt = 0; iCnt < numRoots; iCnt++) + { + if (NULL != baseLineCerts[iCnt]) + { + CFRelease(baseLineCerts[iCnt]); + } + } + } + // The request is for the current certificates. + else + { + CFErrorRef error = NULL; + CFArrayRef cert_datas = CopyEscrowCertificates(escrowRootType, &error); + if (NULL != error || NULL == cert_datas || 0 == (numRoots = (int)CFArrayGetCount(cert_datas))) + { + if (NULL != error) + { + CFRelease(error); + } + + if (NULL != cert_datas) + { + CFRelease(cert_datas); + } + return result; + } + + SecCertificateRef assetCerts[numRoots]; + for (iCnt = 0; iCnt < numRoots; iCnt++) + { + certData = (CFDataRef)CFArrayGetValueAtIndex(cert_datas, iCnt); + if (NULL != certData) + { + SecCertificateRef aCertRef = SecCertificateCreateWithData(kCFAllocatorDefault, certData); + assetCerts[iCnt] = aCertRef; + } + else + { + assetCerts[iCnt] = NULL; + } + } + + if (numRoots > 0) + { + result = CFArrayCreate(kCFAllocatorDefault, (const void **)assetCerts, numRoots, &kCFTypeArrayCallBacks); + for (iCnt = 0; iCnt < numRoots; iCnt++) + { + if (NULL != assetCerts[iCnt]) + { + CFRelease(assetCerts[iCnt]); + } + } + } + CFRelease(cert_datas); + } + + return result; +} +#endif + +#if !SECTRUST_OSX +/* new in 10.11 */ +SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate) +{ + SecSignatureHashAlgorithm result = kSecSignatureHashAlgorithmUnknown; + CSSM_X509_ALGORITHM_IDENTIFIER_PTR algId = NULL; + CSSM_DATA_PTR fieldValue = NULL; + CSSM_OID_PTR algOID = NULL; + const CSSM_OID *sigAlgOID = &CSSMOID_X509V1SignatureAlgorithm; + OSStatus status; + + status = SecCertificateCopyFirstFieldValue(certificate, sigAlgOID, &fieldValue); + if (status || !fieldValue) { + return result; + } + algId = (CSSM_X509_ALGORITHM_IDENTIFIER_PTR)fieldValue->Data; + algOID = (algId) ? &algId->algorithm : NULL; + + while (algOID) { + if (!algOID->Data || !algOID->Length) { + break; + } + /* classify the signature algorithm OID into one of our known types */ + if (cuCompareCssmData(algOID, &CSSMOID_ECDSA_WithSHA512) || + cuCompareCssmData(algOID, &CSSMOID_SHA512WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_SHA512)) { + result = kSecSignatureHashAlgorithmSHA512; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_ECDSA_WithSHA384) || + cuCompareCssmData(algOID, &CSSMOID_SHA384WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_SHA384)) { + result = kSecSignatureHashAlgorithmSHA384; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_ECDSA_WithSHA256) || + cuCompareCssmData(algOID, &CSSMOID_SHA256WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_SHA256)) { + result = kSecSignatureHashAlgorithmSHA256; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_ECDSA_WithSHA224) || + cuCompareCssmData(algOID, &CSSMOID_SHA224WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_SHA224)) { + result = kSecSignatureHashAlgorithmSHA224; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_ECDSA_WithSHA1) || + cuCompareCssmData(algOID, &CSSMOID_SHA1WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_SHA1WithDSA) || + cuCompareCssmData(algOID, &CSSMOID_SHA1WithDSA_CMS) || + cuCompareCssmData(algOID, &CSSMOID_SHA1WithDSA_JDK) || + cuCompareCssmData(algOID, &CSSMOID_SHA1WithRSA_OIW) || + cuCompareCssmData(algOID, &CSSMOID_APPLE_FEE_SHA1) || + cuCompareCssmData(algOID, &CSSMOID_SHA1)) { + result = kSecSignatureHashAlgorithmSHA1; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_MD5WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_APPLE_FEE_MD5) || + cuCompareCssmData(algOID, &CSSMOID_MD5)) { + result = kSecSignatureHashAlgorithmMD5; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_MD4WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_MD4)) { + result = kSecSignatureHashAlgorithmMD4; + break; + } + if (cuCompareCssmData(algOID, &CSSMOID_MD2WithRSA) || + cuCompareCssmData(algOID, &CSSMOID_MD2)) { + result = kSecSignatureHashAlgorithmMD2; + break; + } + break; + } + + (void)SecCertificateReleaseFirstFieldValue(certificate, sigAlgOID, fieldValue); + + return result; +} +#endif +