X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195..e3d3b979fd185d8303f28a937baa53a187fb8c7d:/libsecurity_keychain/lib/TrustAdditions.cpp?ds=sidebyside diff --git a/libsecurity_keychain/lib/TrustAdditions.cpp b/libsecurity_keychain/lib/TrustAdditions.cpp index 0f36410c..6fffe9cb 100644 --- a/libsecurity_keychain/lib/TrustAdditions.cpp +++ b/libsecurity_keychain/lib/TrustAdditions.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include // for CSSM_APPLE_TP_OCSP_OPTIONS, CSSM_APPLE_TP_OCSP_OPT_FLAGS @@ -58,8 +59,15 @@ } /* 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 _(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; }