]> git.saurik.com Git - apple/security.git/blobdiff - libsecurity_keychain/lib/TrustAdditions.cpp
Security-55471.14.8.tar.gz
[apple/security.git] / libsecurity_keychain / lib / TrustAdditions.cpp
index 0f36410c96462704f901c4b190d8e22b905d16f7..6fffe9cb9e4f7cadf5ec31904d59d999f285b15d 100644 (file)
@@ -41,6 +41,7 @@
 #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
@@ -99,7 +107,7 @@ static CFDataRef dataWithContentsOfFile(const char *fileName)
        int rtn;
        int fd;
        struct stat     sb;
-       off_t fileSize;
+       size_t fileSize;
        UInt8 *fileData = NULL;
        CFDataRef outCFData = NULL;
 
@@ -111,16 +119,16 @@ static CFDataRef dataWithContentsOfFile(const char *fileName)
        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 {
@@ -141,14 +149,14 @@ static SecKeychainRef systemRootStore()
 {
     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
@@ -165,7 +173,7 @@ static SecKeychainRef systemRootStore()
                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
@@ -207,7 +215,7 @@ static CFDictionaryRef dictionaryWithContentsOfPlistFile(const char *fileName)
 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;
@@ -376,7 +384,7 @@ static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificate
     // 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
@@ -423,18 +431,18 @@ static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificate
             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;
@@ -494,7 +502,7 @@ static void logSKID(const char *msg, const CssmData &subjectKeyID)
 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);
@@ -509,7 +517,7 @@ void showCertSKID(const void *value, void *context)
 static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertificateRef certificate)
 {
     SecCertificateRef resultCert = NULL;
-       OSStatus status = noErr;
+       OSStatus status = errSecSuccess;
 
     if (!certificate)
         return NULL;
@@ -544,6 +552,7 @@ static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertif
 // 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());
@@ -564,7 +573,7 @@ CFArrayRef _possibleRootCertificatesForOidString(CFStringRef oidString)
        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);
@@ -602,9 +611,9 @@ CFArrayRef _possibleRootCertificatesForOidString(CFStringRef oidString)
                                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);
@@ -660,7 +669,7 @@ CFArrayRef _allowedRootCertificatesForOidString(CFStringRef oidString)
                                        &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
@@ -838,7 +847,7 @@ bool ignorableRevocationStatusCode(CSSM_RETURN statusCode)
                return (ocspRequired) ? false : true;
        if (isCRLStatusCode(statusCode))
                return (crlRequired) ? false : true;
+
        return false;
 }
 
@@ -866,7 +875,7 @@ CFArrayRef allowedEVRootsForLeafCertificate(CFArrayRef certificates)
     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
@@ -909,10 +918,43 @@ CFArrayRef allowedEVRootsForLeafCertificate(CFArrayRef certificates)
        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
@@ -941,8 +983,8 @@ CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultTy
        //
     // 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
@@ -952,6 +994,10 @@ CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultTy
     // - 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
@@ -961,7 +1007,13 @@ CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultTy
     //      - 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;
@@ -970,7 +1022,7 @@ CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultTy
        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
@@ -1011,6 +1063,7 @@ CFDictionaryRef extendedValidationResults(CFArrayRef certChain, SecTrustResultTy
                        CFMutableDictionaryRef resultDict = CFDictionaryCreateMutable(NULL, 0,
                                &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                        CFDictionaryAddValue(resultDict, kSecEVOrganizationName, organizationName);
+                       trustDebug("[EV] extended validation succeeded");
                        SafeCFRelease(&organizationName);
                        return resultDict;
                }