#include <AvailabilityMacros.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonDigest.h>
+#include <Security/SecBase.h>
#include <Security/Security.h>
#include <Security/cssmtype.h>
#include <Security/cssmapplePriv.h> // for CSSM_APPLE_TP_OCSP_OPTIONS, CSSM_APPLE_TP_OCSP_OPT_FLAGS
} /* status is only set on error */ \
catch (const MacOSError &err) { status=err.osStatus(); } \
catch (const CommonError &err) { status=SecKeychainErrFromOSStatus(err.osStatus()); } \
- catch (const std::bad_alloc &) { status=memFullErr; } \
- catch (...) { status=internalComponentErr; }
+ catch (const std::bad_alloc &) { status=errSecAllocate; } \
+ catch (...) { status=errSecInternalComponent; }
+
+#ifdef NDEBUG
+/* this actually compiles to nothing */
+#define trustDebug(args...) secdebug("trust", ## args)
+#else
+#define trustDebug(args...) printf(args)
+#endif
//
// Static constants
int rtn;
int fd;
struct stat sb;
- off_t fileSize;
+ size_t fileSize;
UInt8 *fileData = NULL;
CFDataRef outCFData = NULL;
if(rtn)
goto errOut;
- fileSize = sb.st_size;
+ fileSize = (size_t)sb.st_size;
fileData = (UInt8 *) malloc(fileSize);
if(fileData == NULL)
goto errOut;
- rtn = lseek(fd, 0, SEEK_SET);
+ rtn = (int)lseek(fd, 0, SEEK_SET);
if(rtn < 0)
goto errOut;
- rtn = read(fd, fileData, fileSize);
+ rtn = (int)read(fd, fileData, fileSize);
if(rtn != (int)fileSize) {
rtn = EIO;
} else {
{
SecKeychainStatus keychainStatus = 0;
SecKeychainRef systemRoots = NULL;
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
// note: Sec* APIs are not re-entrant due to the API lock
// status = SecKeychainOpen(SYSTEM_ROOTS_PLIST_SYSTEM_PATH, &systemRoots);
BEGIN_SECAPI_INTERNAL_CALL
systemRoots=globals().storageManager.make(SYSTEM_ROOTS_PLIST_SYSTEM_PATH, false)->handle();
END_SECAPI_INTERNAL_CALL
- // SecKeychainOpen will return noErr even if the file didn't exist on disk.
+ // SecKeychainOpen will return errSecSuccess even if the file didn't exist on disk.
// We need to do a further check using SecKeychainGetStatus().
if (!status && systemRoots) {
// note: Sec* APIs are not re-entrant due to the API lock
BEGIN_SECAPI_INTERNAL_CALL
systemRoots=globals().storageManager.make(X509ANCHORS_SYSTEM_PATH, false)->handle();
END_SECAPI_INTERNAL_CALL
- // SecKeychainOpen will return noErr even if the file didn't exist on disk.
+ // SecKeychainOpen will return errSecSuccess even if the file didn't exist on disk.
// We need to do a further check using SecKeychainGetStatus().
if (!status && systemRoots) {
// note: Sec* APIs are not re-entrant due to the API lock
static CFStringRef organizationNameForCertificate(SecCertificateRef certificate)
{
CFStringRef organizationName = nil;
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_OrganizationName;
// get data+length for the provided certificate
CSSM_CL_HANDLE clHandle = 0;
CSSM_DATA certData = { 0, NULL };
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
// note: Sec* APIs are not re-entrant due to the API lock
// status = SecCertificateGetCLHandle(certificate, &clHandle);
BEGIN_SECAPI_INTERNAL_CALL
uint8 buf[CC_SHA1_DIGEST_LENGTH];
CSSM_DATA digest = { sizeof(buf), buf };
if (!cssmKey || !cssmKey->KeyData.Data || !cssmKey->KeyData.Length) {
- status = paramErr;
+ status = errSecParam;
} else {
- CC_SHA1(cssmKey->KeyData.Data, cssmKey->KeyData.Length, buf);
+ CC_SHA1(cssmKey->KeyData.Data, (CC_LONG)cssmKey->KeyData.Length, buf);
}
if (!status) {
// set up attribute vector (each attribute consists of {tag, length, pointer})
// we want to match on the public key hash and the normalized subject name
// as well as ensure that the issuer matches the subject
SecKeychainAttribute attrs[] = {
- { kSecPublicKeyHashItemAttr, digest.Length, (void *)digest.Data },
- { kSecSubjectItemAttr, subjectDataPtr->Length, (void *)subjectDataPtr->Data },
- { kSecIssuerItemAttr, subjectDataPtr->Length, (void *)subjectDataPtr->Data }
+ { kSecPublicKeyHashItemAttr, (UInt32)digest.Length, (void *)digest.Data },
+ { kSecSubjectItemAttr, (UInt32)subjectDataPtr->Length, (void *)subjectDataPtr->Data },
+ { kSecIssuerItemAttr, (UInt32)subjectDataPtr->Length, (void *)subjectDataPtr->Data }
};
const SecKeychainAttributeList attributes = { sizeof(attrs) / sizeof(attrs[0]), attrs };
SecKeychainSearchRef searchRef = NULL;
void showCertSKID(const void *value, void *context)
{
SecCertificateRef certificate = (SecCertificateRef)value;
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
BEGIN_SECAPI_INTERNAL_CALL
const CssmData &subjectKeyID = Certificate::required(certificate)->subjectKeyIdentifier();
logSKID("subjectKeyID: ", subjectKeyID);
static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertificateRef certificate)
{
SecCertificateRef resultCert = NULL;
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
if (!certificate)
return NULL;
// returns an array of possible root certificates (SecCertificateRef instances)
// for the given EV OID (a hex string); caller must release the array
//
+static
CFArrayRef _possibleRootCertificatesForOidString(CFStringRef oidString)
{
StLock<Mutex> _(SecTrustKeychainsGetMutex());
CFIndex hashCount = CFArrayGetCount(possibleCertificateHashes);
secdebug("evTrust", "_possibleRootCertificatesForOidString: %d possible hashes", (int)hashCount);
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
SecKeychainSearchRef searchRef = NULL;
// note: Sec* APIs are not re-entrant due to the API lock
// status = SecKeychainSearchCreateFromAttributes(systemRoots, kSecCertificateItemClass, NULL, &searchRef);
uint8 buf[CC_SHA1_DIGEST_LENGTH];
CSSM_DATA digest = { sizeof(buf), buf };
if (!certData.Data || !certData.Length) {
- status = paramErr;
+ status = errSecParam;
} else {
- CC_SHA1(certData.Data, certData.Length, buf);
+ CC_SHA1(certData.Data, (CC_LONG)certData.Length, buf);
}
if (!status) {
CFDataRef hashData = CFDataCreateWithBytesNoCopy(NULL, digest.Data, digest.Length, kCFAllocatorNull);
&foundMatch, /* foundMatchingEntry */
&foundAny); /* foundAnyEntry */
- if (status == noErr) {
+ if (status == errSecSuccess) {
secdebug("evTrust", "_allowedRootCertificatesForOidString: cert %lu has result %d from domain %d",
idx, (int)result, (int)foundDomain);
// Root certificates must be trusted by the system (and not have
return (ocspRequired) ? false : true;
if (isCRLStatusCode(statusCode))
return (crlRequired) ? false : true;
-
+
return false;
}
CSSM_CL_HANDLE clHandle = 0;
CSSM_DATA certData = { 0, NULL };
SecCertificateRef certRef = (SecCertificateRef) CFArrayGetValueAtIndex(certificates, 0);
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
// note: Sec* APIs are not re-entrant due to the API lock
// status = SecCertificateGetCLHandle(certRef, &clHandle);
BEGIN_SECAPI_INTERNAL_CALL
return allowedRoots;
}
+// returns true if the provided certificate contains a wildcard in either
+// its common name or subject alternative name.
+//
+static
+bool hasWildcardDNSName(SecCertificateRef certRef)
+{
+ OSStatus status = errSecSuccess;
+ CFArrayRef dnsNames = NULL;
+
+ BEGIN_SECAPI_INTERNAL_CALL
+ Required(&dnsNames) = Certificate::required(certRef)->copyDNSNames();
+ END_SECAPI_INTERNAL_CALL
+ if (status || !dnsNames)
+ return false;
+
+ bool hasWildcard = false;
+ const CFStringRef wildcard = CFSTR("*");
+ CFIndex index, count = CFArrayGetCount(dnsNames);
+ for (index = 0; index < count; index ++) {
+ CFStringRef name = (CFStringRef) CFArrayGetValueAtIndex(dnsNames, index);
+ if (name) {
+ CFRange foundRange = CFStringFind(name, wildcard, 0);
+ if (foundRange.length != 0 && foundRange.location != kCFNotFound) {
+ hasWildcard = true;
+ break;
+ }
+ }
+ }
+ CFRelease(dnsNames);
+ return hasWildcard;
+}
+
// returns a CFDictionaryRef of extended validation results for the given chain,
// or NULL if the certificate chain did not meet all EV criteria. (Caller must
// release the result if not NULL.)
//
+static
CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultType trustResult, OSStatus tpResult)
{
// This function is intended to be called after the "regular" TP evaluation
//
// What we know at this point:
//
- // 1. From a previous call to _leafCertificateMeetsExtendedValidationCriteria
- // (or we wouldn't be calling _chainMeetsExtendedValidationCriteria!):
+ // 1. From a previous call to allowedEVRootsForLeafCertificate
+ // (or we wouldn't be getting called by extendedTrustResults):
// - a leaf certificate exists
// - that certificate contains a Certificate Policies extension
// - that extension contains an OID from one of the trusted EV CAs we know about
// - the leaf certificate verifies back to a trusted EV root (with no trust settings overrides)
// - SSL trust evaluation with OCSP revocation checking enabled returned no (fatal) errors
//
+ // We need to verify the following additional requirements for the leaf (as of EV 1.1, 6(a)(2)):
+ // - cannot specify a wildcard in commonName or subjectAltName
+ // (note: this is a change since EV 1.0 (9.2.1), which stated that "Wildcard FQDNs are permitted.")
+ //
// Finally, we need to check the following requirements (EV 1.1 specification, Appendix B):
// - the trusted root, if created after 10/31/2006, must have:
// - critical basicConstraints extension with CA bit set
// - non-critical cRLDistributionPoint extension
// - critical basicConstraints extension with CA bit set
// - critical keyUsage extension with keyCertSign and cRLSign bits set
- //
+ //
+
+ // check leaf certificate for wildcard names
+ if (hasWildcardDNSName((SecCertificateRef) CFArrayGetValueAtIndex(certChain, 0))) {
+ trustDebug("has wildcard name (does not meet EV criteria)");
+ return NULL;
+ }
// check intermediate CA certificates for required extensions per Appendix B of EV 1.1 specification.
bool hasRequiredExtensions = true;
CSSM_OID_PTR oidPtr = (CSSM_OID_PTR) &CSSMOID_CertificatePolicies;
for (chainIndex = 1; hasRequiredExtensions && chainLen > 2 && chainIndex < chainLen - 1; chainIndex++) {
SecCertificateRef intermediateCert = (SecCertificateRef) CFArrayGetValueAtIndex(certChain, chainIndex);
- OSStatus status = noErr;
+ OSStatus status = errSecSuccess;
// note: Sec* APIs are not re-entrant due to the API lock
// status = SecCertificateGetCLHandle(intermediateCert, &clHandle);
BEGIN_SECAPI_INTERNAL_CALL
CFMutableDictionaryRef resultDict = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(resultDict, kSecEVOrganizationName, organizationName);
+ trustDebug("[EV] extended validation succeeded");
SafeCFRelease(&organizationName);
return resultDict;
}