SecCertificate.cpp [plain text]
#include <Security/SecCertificate.h>
#include <Security/SecCertificatePriv.h>
#include <security_keychain/Certificate.h>
#include <security_keychain/Item.h>
#include <security_keychain/KCCursor.h>
#include <Security/cssmapi.h>
#include <Security/cssmapple.h>
#include <security_cdsa_client/cspclient.h>
#include <security_cdsa_client/clclient.h>
#include <security_cdsa_client/tpclient.h>
#include <Security/cssmtype.h>
#include "SecBridge.h"
#include <Security/SecKeychainItemPriv.h>
#include <Security/SecIdentityPriv.h>
#include <security_keychain/KCCursor.h>
#include <security_cdsa_utilities/Schema.h>
#include <security_cdsa_utils/cuCdsaUtils.h>
#include <sys/param.h>
#include <syslog.h>
#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
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<Certificate> certificatePtr(new Certificate(cssmCertData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER));
implCertRef = certificatePtr->handle();
}
catch (...) {}
CFRelease(data);
return implCertRef;
#endif
}
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) {
}
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
}
OSStatus
SecCertificateCreateFromData(const CSSM_DATA *data, CSSM_CERT_TYPE type, CSSM_CERT_ENCODING encoding, SecCertificateRef *certificate)
{
#if !SECTRUST_OSX
BEGIN_SECAPI
SecPointer<Certificate> certificatePtr(new Certificate(Required(data), type, encoding));
Required(certificate) = certificatePtr->handle();
END_SECAPI
#else
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
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;
SecPointer<Certificate> 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
OSStatus
SecCertificateAddToKeychain(SecCertificateRef certificate, SecKeychainRef keychain)
{
BEGIN_SECCERTAPI
Item item(Certificate::required(__itemImplRef));
Keychain::optional(keychain)->add(item);
END_SECCERTAPI
}
OSStatus
SecCertificateGetData(SecCertificateRef certificate, CSSM_DATA_PTR data)
{
BEGIN_SECCERTAPI
Required(data) = Certificate::required(__itemImplRef)->data();
END_SECCERTAPI
}
#if !SECTRUST_OSX
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
OSStatus
SecCertificateGetType(SecCertificateRef certificate, CSSM_CERT_TYPE *certificateType)
{
BEGIN_SECCERTAPI
Required(certificateType) = Certificate::required(__itemImplRef)->type();
END_SECCERTAPI
}
OSStatus
SecCertificateGetSubject(SecCertificateRef certificate, const CSSM_X509_NAME **subject)
{
BEGIN_SECCERTAPI
Required(subject) = Certificate::required(__itemImplRef)->subjectName();
END_SECCERTAPI
}
OSStatus
SecCertificateGetIssuer(SecCertificateRef certificate, const CSSM_X509_NAME **issuer)
{
BEGIN_SECCERTAPI
Required(issuer) = Certificate::required(__itemImplRef)->issuerName();
END_SECCERTAPI
}
OSStatus
SecCertificateGetCLHandle(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle)
{
#if !SECTRUST_OSX
BEGIN_SECAPI
Required(clHandle) = Certificate::required(certificate)->clHandle();
END_SECAPI
#else
#if 0
BEGIN_SECCERTAPI
Required(clHandle) = Certificate::required(__itemImplRef)->clHandle();
END_SECCERTAPI
#endif
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) {
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
}
OSStatus
SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle)
{
BEGIN_SECAPI
Required(clHandle) = Certificate::required(certificate)->clHandle();
END_SECAPI
}
OSStatus
SecCertificateInferLabel(SecCertificateRef certificate, CFStringRef *label)
{
BEGIN_SECCERTAPI
Certificate::required(__itemImplRef)->inferLabel(false, &Required(label));
END_SECCERTAPI
}
OSStatus
SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef *key)
{
BEGIN_SECCERTAPI
Required(key) = Certificate::required(__itemImplRef)->publicKey()->handle();
END_SECCERTAPI
}
OSStatus
SecCertificateGetAlgorithmID(SecCertificateRef certificate, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
{
BEGIN_SECCERTAPI
Required(algid) = Certificate::required(__itemImplRef)->algorithmID();
END_SECCERTAPI
}
OSStatus
SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef *commonName)
{
BEGIN_SECCERTAPI
Required(commonName) = Certificate::required(__itemImplRef)->commonName();
END_SECCERTAPI
}
#if !SECTRUST_OSX
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
OSStatus
SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component, CFStringRef *result)
{
BEGIN_SECCERTAPI
Required(result) = Certificate::required(__itemImplRef)->distinguishedName(&CSSMOID_X509V1SubjectNameCStruct, component);
END_SECCERTAPI
}
OSStatus
SecCertificateGetCommonName(SecCertificateRef certificate, CFStringRef *commonName)
{
return SecCertificateCopyCommonName(certificate, commonName);
}
OSStatus
SecCertificateGetEmailAddress(SecCertificateRef certificate, CFStringRef *emailAddress)
{
BEGIN_SECCERTAPI
Required(emailAddress) = Certificate::required(__itemImplRef)->copyFirstEmailAddress();
END_SECCERTAPI
}
OSStatus
SecCertificateCopyEmailAddresses(SecCertificateRef certificate, CFArrayRef *emailAddresses)
{
BEGIN_SECCERTAPI
Required(emailAddresses) = Certificate::required(__itemImplRef)->copyEmailAddresses();
END_SECCERTAPI
}
OSStatus
SecCertificateCopyFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR **fieldValues)
{
BEGIN_SECCERTAPI
Required(fieldValues) = Certificate::required(__itemImplRef)->copyFieldValues(Required(field));
END_SECCERTAPI
}
OSStatus
SecCertificateReleaseFieldValues(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValues)
{
BEGIN_SECCERTAPI
Certificate::required(__itemImplRef)->releaseFieldValues(Required(field), fieldValues);
END_SECCERTAPI
}
OSStatus
SecCertificateCopyFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR *fieldValue)
{
BEGIN_SECCERTAPI
Required(fieldValue) = Certificate::required(__itemImplRef)->copyFirstFieldValue(Required(field));
END_SECCERTAPI
}
OSStatus
SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, const CSSM_OID *field, CSSM_DATA_PTR fieldValue)
{
BEGIN_SECCERTAPI
Certificate::required(__itemImplRef)->releaseFieldValue(Required(field), fieldValue);
END_SECCERTAPI
}
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
CssmData certData = Certificate::required(*certificate)->data();
CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length));
SecCertificateRef tmpRef = *certificate;
*certificate = SecCertificateCreateWithData(NULL, cfData);
CFRelease(tmpRef);
#endif
END_SECAPI
}
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
CssmData certData = Certificate::required(*certificate)->data();
CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length));
SecCertificateRef tmpRef = *certificate;
*certificate = SecCertificateCreateWithData(NULL, cfData);
CFRelease(tmpRef);
#endif
END_SECAPI
}
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
CssmData certData = Certificate::required(*certificate)->data();
CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length));
SecCertificateRef tmpRef = *certificate;
*certificate = SecCertificateCreateWithData(NULL, cfData);
CFRelease(tmpRef);
#endif
END_SECAPI
}
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
}
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
}
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
}
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
}
CSSM_RETURN
SecDigestGetData (CSSM_ALGORITHMS alg, CSSM_DATA* digest, const CSSM_DATA* data)
{
BEGIN_SECAPI
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
OSStatus SecCertificateIsSelfSigned(
SecCertificateRef certificate,
Boolean *isSelfSigned)
{
BEGIN_SECAPI
*isSelfSigned = Certificate::required(certificate)->isSelfSigned();
END_SECAPI
}
#endif
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<char *>(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);
SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } };
SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
prefItem->getContent(NULL, &itemAttrList, NULL, NULL);
CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull);
SecKeychainItemRef certItemRef = nil;
OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); prefItem->freeContent(&itemAttrList, NULL);
if (pItemRef)
CFRelease(pItemRef);
if (status)
return status;
*certificate = (SecCertificateRef)certItemRef;
#if SECTRUST_OSX
CssmData certData = Certificate::required(*certificate)->data();
CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length));
SecCertificateRef tmpRef = *certificate;
*certificate = SecCertificateCreateWithData(NULL, cfData);
CFRelease(tmpRef);
#endif
END_SECAPI
}
SecCertificateRef
SecCertificateCopyPreferred(
CFStringRef name,
CFArrayRef keyUsage)
{
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;
}
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<char *>(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
}
static
OSStatus SecCertificateDeletePreferenceItemWithNameAndKeyUsage(
CFTypeRef keychainOrArray,
CFStringRef name,
int32_t keyUsage)
{
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;
}
return (status == errSecItemNotFound) ? errSecSuccess : status;
}
OSStatus SecCertificateSetPreference(
SecCertificateRef certificate,
CFStringRef name,
CSSM_KEYUSE keyUsage,
CFDateRef date)
{
if (!name) {
return errSecParam;
}
if (!certificate) {
return SecCertificateDeletePreferenceItemWithNameAndKeyUsage(NULL, name, keyUsage);
}
BEGIN_SECCERTAPI
CFStringRef labelStr = nil;
Certificate::required(__itemImplRef)->inferLabel(false, &labelStr);
if (!labelStr) {
MacOSError::throwMe(errSecDataTooLarge); }
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<char *>(accountUTF8), strlen(accountUTF8));
CFRelease(labelStr);
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<char *>(serviceUTF8), strlen(serviceUTF8));
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)
;
Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false);
bool add = (!cursor->next(item));
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);
if (date)
;
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<void *>(reinterpret_cast<const void *>(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); }
catch(...) {
keychain = globals().storageManager.defaultKeychainUI(item);
}
try {
keychain->add(item);
}
catch (const MacOSError &err) {
if (err.osStatus() != errSecDuplicateItem)
throw; }
}
item->update();
END_SECCERTAPI
}
OSStatus SecCertificateSetPreferred(
SecCertificateRef certificate,
CFStringRef name,
CFArrayRef keyUsage)
{
CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage);
return SecCertificateSetPreference(certificate, name, keyUse, NULL);
}
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;
}
CFStringRef SecCertificateCopyLongDescription(CFAllocatorRef alloc, SecCertificateRef certificate, CFErrorRef *error)
{
return SecCertificateCopyShortDescription(alloc, certificate, error);
}
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;
}
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;
}
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;
}
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
bool SecCertificateIsValidX(SecCertificateRef certificate, CFAbsoluteTime verifyTime)
{
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
SecCertificateRef SecCertificateCreateWithBytes(CFAllocatorRef allocator,
const UInt8 *bytes, CFIndex length)
{
SecCertificateRef certificate = NULL;
OSStatus __secapiresult;
try {
CSSM_DATA cssmCertData = { (CSSM_SIZE)length, (uint8 *)bytes };
SecPointer<Certificate> 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
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
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
static CFArrayRef CopyEscrowCertificates(SecCertificateEscrowRootType escrowRootType, CFErrorRef *error)
{
CFArrayRef result = NULL;
int iCnt;
int numRoots = 0;
struct RootRecord** pEscrowRoots = NULL;
switch (escrowRootType) {
case kSecCertificateBaselineEscrowRoot:
numRoots = kNumberOfBaseLineEscrowRoots;
pEscrowRoots = kBaseLineEscrowRoots;
break;
case kSecCertificateProductionEscrowRoot:
numRoots = kNumberOfBaseLineEscrowRoots; pEscrowRoots = kBaseLineEscrowRoots;
break;
case kSecCertificateBaselinePCSEscrowRoot:
numRoots = kNumberOfBaseLinePCSEscrowRoots;
pEscrowRoots = kBaseLinePCSEscrowRoots;
break;
case kSecCertificateProductionPCSEscrowRoot:
numRoots = kNumberOfBaseLinePCSEscrowRoots; 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
CFArrayRef SecCertificateCopyEscrowRoots(SecCertificateEscrowRootType escrowRootType)
{
CFArrayRef result = NULL;
int iCnt;
int numRoots = 0;
CFDataRef certData = NULL;
if (kSecCertificateBaselineEscrowRoot == escrowRootType)
{
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]);
}
}
}
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
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;
}
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