X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/67d61d2eddbf13b089421b1c08b0353e50c467d7..refs/heads/master:/trust/trustd/SecPolicyServer.c?ds=inline diff --git a/trust/trustd/SecPolicyServer.c b/trust/trustd/SecPolicyServer.c index e0abcb94..063b0e1b 100644 --- a/trust/trustd/SecPolicyServer.c +++ b/trust/trustd/SecPolicyServer.c @@ -25,25 +25,33 @@ * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies. */ -#include "trust/trustd/SecPolicyServer.h" -#include -#include -#include -#include "trust/trustd/policytree.h" -#include "trust/trustd/nameconstraints.h" -#include +#include #include -#include +#include + +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include #include #include #include #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -51,9 +59,10 @@ #include #include #include -#include -#include -#include + +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/policytree.h" +#include "trust/trustd/nameconstraints.h" #include "trust/trustd/SecTrustServer.h" #include "trust/trustd/SecTrustLoggingServer.h" #include "trust/trustd/SecRevocationServer.h" @@ -61,12 +70,9 @@ #include "trust/trustd/SecCertificateSource.h" #include "trust/trustd/SecOCSPResponse.h" #include "trust/trustd/SecTrustStoreServer.h" -#include -#include -#include -#include "OTATrustUtilities.h" -#include "personalization.h" -#include +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/personalization.h" +#include "trust/trustd/CertificateTransparency.h" #if !TARGET_OS_IPHONE #include @@ -95,9 +101,6 @@ static void secdumpdata(CFDataRef data, const char *name) { ****************** SecPolicy object ******************** ********************************************************/ -static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix); -static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc); -static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc); static SecTrustSettingsResult SecPVCGetTrustSettingsResult(SecPVCRef pvc, SecCertificateRef certificate, CFArrayRef constraints); static CFMutableDictionaryRef gSecPolicyLeafCallbacks = NULL; @@ -1328,633 +1331,6 @@ certificatePolicies or extendedKeyUsage extensions. */ } - -/* - * MARK: Certificate Transparency support - */ -const CFStringRef kSecCTRetirementDateKey = CFSTR("expiry"); // For backwards compatibility, retirement date is represented with the "expiry" key -const CFStringRef kSecCTReadOnlyDateKey = CFSTR("frozen"); // For backwards compatibility, read-only date is represented with the "frozen" key -const CFStringRef kSecCTShardStartDateKey = CFSTR("start_inclusive"); -const CFStringRef kSecCTShardEndDateKey = CFSTR("end_exclusive"); -const CFStringRef kSecCTPublicKeyKey = CFSTR("key"); - -enum { - kSecCTEntryTypeCert = 0, - kSecCTEntryTypePreCert = 1, -}; - -/*** - -struct { - Version sct_version; // 1 byte - LogID id; // 32 bytes - uint64 timestamp; // 8 bytes - CtExtensions extensions; // 2 bytes len field, + n bytes data - digitally-signed struct { // 1 byte hash alg, 1 byte sig alg, n bytes signature - Version sct_version; - SignatureType signature_type = certificate_timestamp; - uint64 timestamp; - LogEntryType entry_type; - select(entry_type) { - case x509_entry: ASN.1Cert; - case precert_entry: PreCert; - } signed_entry; - CtExtensions extensions; - }; -} SignedCertificateTimestamp; - -***/ - -#include - -static const -SecAsn1Oid *oidForSigAlg(SSL_HashAlgorithm hash, SSL_SignatureAlgorithm alg) -{ - switch(alg) { - case SSL_SignatureAlgorithmRSA: - switch (hash) { - case SSL_HashAlgorithmSHA1: - return &CSSMOID_SHA1WithRSA; - case SSL_HashAlgorithmSHA256: - return &CSSMOID_SHA256WithRSA; - case SSL_HashAlgorithmSHA384: - return &CSSMOID_SHA384WithRSA; - default: - break; - } - case SSL_SignatureAlgorithmECDSA: - switch (hash) { - case SSL_HashAlgorithmSHA1: - return &CSSMOID_ECDSA_WithSHA1; - case SSL_HashAlgorithmSHA256: - return &CSSMOID_ECDSA_WithSHA256; - case SSL_HashAlgorithmSHA384: - return &CSSMOID_ECDSA_WithSHA384; - default: - break; - } - default: - break; - } - - return NULL; -} - - -static size_t SSLDecodeUint16(const uint8_t *p) -{ - return (p[0]<<8 | p[1]); -} - -static uint8_t *SSLEncodeUint16(uint8_t *p, size_t len) -{ - p[0] = (len >> 8)&0xff; - p[1] = (len & 0xff); - return p+2; -} - -static uint8_t *SSLEncodeUint24(uint8_t *p, size_t len) -{ - p[0] = (len >> 16)&0xff; - p[1] = (len >> 8)&0xff; - p[2] = (len & 0xff); - return p+3; -} - - -static -uint64_t SSLDecodeUint64(const uint8_t *p) -{ - uint64_t u = 0; - for(int i=0; i<8; i++) { - u=(u<<8)|p[0]; - p++; - } - return u; -} - -#include -#include -#include - - -static CFDataRef copy_x509_entry_from_chain(SecPVCRef pvc) -{ - SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - - CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 3+SecCertificateGetLength(leafCert)); - - CFDataSetLength(data, 3+SecCertificateGetLength(leafCert)); - - uint8_t *q = CFDataGetMutableBytePtr(data); - q = SSLEncodeUint24(q, SecCertificateGetLength(leafCert)); - memcpy(q, SecCertificateGetBytePtr(leafCert), SecCertificateGetLength(leafCert)); - - return data; -} - - -static CFDataRef copy_precert_entry_from_chain(SecPVCRef pvc) -{ - SecCertificateRef leafCert = NULL; - SecCertificateRef issuer = NULL; - CFDataRef issuerKeyHash = NULL; - CFDataRef tbs_precert = NULL; - CFMutableDataRef data= NULL; - - require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts. - leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - issuer = SecPVCGetCertificateAtIndex(pvc, 1); - - require(leafCert, out); - require(issuer, out); // Those two would likely indicate an internal error, since we already checked the chain length above. - issuerKeyHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(issuer); - tbs_precert = SecCertificateCopyPrecertTBS(leafCert); - - require(issuerKeyHash, out); - require(tbs_precert, out); - data = CFDataCreateMutable(kCFAllocatorDefault, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert)); - CFDataSetLength(data, CFDataGetLength(issuerKeyHash) + 3 + CFDataGetLength(tbs_precert)); - - uint8_t *q = CFDataGetMutableBytePtr(data); - memcpy(q, CFDataGetBytePtr(issuerKeyHash), CFDataGetLength(issuerKeyHash)); q += CFDataGetLength(issuerKeyHash); // issuer key hash - q = SSLEncodeUint24(q, CFDataGetLength(tbs_precert)); - memcpy(q, CFDataGetBytePtr(tbs_precert), CFDataGetLength(tbs_precert)); - -out: - CFReleaseSafe(issuerKeyHash); - CFReleaseSafe(tbs_precert); - return data; -} - -static -CFAbsoluteTime TimestampToCFAbsoluteTime(uint64_t ts) -{ - return (ts / 1000) - kCFAbsoluteTimeIntervalSince1970; -} - -static -uint64_t TimestampFromCFAbsoluteTime(CFAbsoluteTime at) -{ - return (uint64_t)(at + kCFAbsoluteTimeIntervalSince1970) * 1000; -} - -static bool isSCTValidForLogData(CFDictionaryRef logData, int entry_type, CFAbsoluteTime sct_time, CFAbsoluteTime cert_expiry_date) { - /* only embedded SCTs can be used from retired logs. */ - if(entry_type==kSecCTEntryTypeCert && CFDictionaryContainsKey(logData, kSecCTRetirementDateKey)) { - return false; - } - - /* SCTs from after the transition to read-only are not valid (and indicate a operator failure) */ - CFDateRef frozen_date = CFDictionaryGetValue(logData, kSecCTReadOnlyDateKey); - if (frozen_date && (sct_time > CFDateGetAbsoluteTime(frozen_date))) { - secerror("Frozen CT log issued SCT after freezing (log=%@)\n", logData); - return false; - } - - /* If the log is temporally sharded, the certificate expiry date must be within the temporal shard window */ - CFDateRef start_inclusive = CFDictionaryGetValue(logData, kSecCTShardStartDateKey); - CFDateRef end_exclusive = CFDictionaryGetValue(logData, kSecCTShardEndDateKey); - if (start_inclusive && (cert_expiry_date < CFDateGetAbsoluteTime(start_inclusive))) { - return false; - } - if (end_exclusive && (cert_expiry_date >= CFDateGetAbsoluteTime(end_exclusive))) { - return false; - } - - return true; -} - - -/* - If the 'sct' is valid, add it to the validatingLogs dictionary. - - Inputs: - - validatingLogs: mutable dictionary to which to add the log that validate this SCT. - - sct: the SCT date - - entry_type: 0 for x509 cert, 1 for precert. - - entry: the cert or precert data. - - vt: verification time timestamp (as used in SCTs: ms since 1970 Epoch) - - trustedLog: Dictionary contain the Trusted Logs. - - The SCT is valid if: - - It decodes properly. - - Its timestamp is less than 'verifyTime'. - - It is signed by a log in 'trustedLogs'. - - If entry_type = 0, the log must be currently qualified. - - If entry_type = 1, the log may be expired. - - If the SCT is valid, it's added to the validatinLogs dictionary using the log dictionary as the key, and the timestamp as value. - If an entry for the same log already existing in the dictionary, the entry is replaced only if the timestamp of this SCT is earlier. - - */ -static CFDictionaryRef getSCTValidatingLog(CFDataRef sct, int entry_type, CFDataRef entry, uint64_t vt, CFAbsoluteTime cert_expiry_date, CFDictionaryRef trustedLogs, CFAbsoluteTime *sct_at) -{ - uint8_t version; - const uint8_t *logID; - const uint8_t *timestampData; - uint64_t timestamp; - size_t extensionsLen; - const uint8_t *extensionsData; - uint8_t hashAlg; - uint8_t sigAlg; - size_t signatureLen; - const uint8_t *signatureData; - SecKeyRef pubKey = NULL; - uint8_t *signed_data = NULL; - const SecAsn1Oid *oid = NULL; - SecAsn1AlgId algId; - CFDataRef logIDData = NULL; - CFDictionaryRef result = 0; - - const uint8_t *p = CFDataGetBytePtr(sct); - size_t len = CFDataGetLength(sct); - - require(len>=43, out); - - version = p[0]; p++; len--; - logID = p; p+=32; len-=32; - timestampData = p; p+=8; len-=8; - extensionsLen = SSLDecodeUint16(p); p+=2; len-=2; - - require(len>=extensionsLen, out); - extensionsData = p; p+=extensionsLen; len-=extensionsLen; - - require(len>=4, out); - hashAlg=p[0]; p++; len--; - sigAlg=p[0]; p++; len--; - signatureLen = SSLDecodeUint16(p); p+=2; len-=2; - require(len==signatureLen, out); /* We do not tolerate any extra data after the signature */ - signatureData = p; - - /* verify version: only v1(0) is supported */ - if(version!=0) { - secerror("SCT version unsupported: %d\n", version); - goto out; - } - - /* verify timestamp not in the future */ - timestamp = SSLDecodeUint64(timestampData); - if(timestamp > vt) { - secerror("SCT is in the future: %llu > %llu\n", timestamp, vt); - goto out; - } - - uint8_t *q; - - /* signed entry */ - size_t signed_data_len = 12 + CFDataGetLength(entry) + 2 + extensionsLen ; - signed_data = malloc(signed_data_len); - require(signed_data, out); - q = signed_data; - *q++ = version; - *q++ = 0; // certificate_timestamp - memcpy(q, timestampData, 8); q+=8; - q = SSLEncodeUint16(q, entry_type); // logentry type: 0=cert 1=precert - memcpy(q, CFDataGetBytePtr(entry), CFDataGetLength(entry)); q += CFDataGetLength(entry); - q = SSLEncodeUint16(q, extensionsLen); - memcpy(q, extensionsData, extensionsLen); - - logIDData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, logID, 32, kCFAllocatorNull); - - CFDictionaryRef logData = CFDictionaryGetValue(trustedLogs, logIDData); - CFAbsoluteTime sct_time = TimestampToCFAbsoluteTime(timestamp); - require(logData && isSCTValidForLogData(logData, entry_type, sct_time, cert_expiry_date), out); - - CFDataRef logKeyData = CFDictionaryGetValue(logData, kSecCTPublicKeyKey); - require(logKeyData, out); // This failing would be an internal logic error - pubKey = SecKeyCreateFromSubjectPublicKeyInfoData(kCFAllocatorDefault, logKeyData); - require(pubKey, out); - - oid = oidForSigAlg(hashAlg, sigAlg); - require(oid, out); - - algId.algorithm = *oid; - algId.parameters.Data = NULL; - algId.parameters.Length = 0; - - if(SecKeyDigestAndVerify(pubKey, &algId, signed_data, signed_data_len, signatureData, signatureLen)==0) { - *sct_at = sct_time; - result = logData; - } else { - secerror("SCT signature failed (log=%@)\n", logData); - } - -out: - CFReleaseSafe(logIDData); - CFReleaseSafe(pubKey); - free(signed_data); - return result; -} - - -static void addValidatingLog(CFMutableDictionaryRef validatingLogs, CFDictionaryRef log, CFAbsoluteTime sct_at) -{ - CFDateRef validated_time = CFDictionaryGetValue(validatingLogs, log); - - if(validated_time==NULL || (sct_at < CFDateGetAbsoluteTime(validated_time))) { - CFDateRef sct_time = CFDateCreate(kCFAllocatorDefault, sct_at); - CFDictionarySetValue(validatingLogs, log, sct_time); - CFReleaseSafe(sct_time); - } -} - -static CFArrayRef copy_ocsp_scts(SecPVCRef pvc) -{ - CFMutableArrayRef SCTs = NULL; - SecCertificateRef leafCert = NULL; - SecCertificateRef issuer = NULL; - CFArrayRef ocspResponsesData = NULL; - SecOCSPRequestRef ocspRequest = NULL; - - ocspResponsesData = SecPathBuilderCopyOCSPResponses(pvc->builder); - require_quiet(ocspResponsesData, out); - - require_quiet(SecPVCGetCertificateCount(pvc)>=2, out); //we need the issuer key for precerts. - leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - issuer = SecPVCGetCertificateAtIndex(pvc, 1); - - require(leafCert, out); - require(issuer, out); // not quiet: Those two would likely indicate an internal error, since we already checked the chain length above. - ocspRequest = SecOCSPRequestCreate(leafCert, issuer); - - SCTs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - require(SCTs, out); - - CFArrayForEach(ocspResponsesData, ^(const void *value) { - /* TODO: Should the builder already have the appropriate SecOCSPResponseRef ? */ - SecOCSPResponseRef ocspResponse = SecOCSPResponseCreate(value); - if(ocspResponse && SecOCSPGetResponseStatus(ocspResponse)==kSecOCSPSuccess) { - SecOCSPSingleResponseRef ocspSingleResponse = SecOCSPResponseCopySingleResponse(ocspResponse, ocspRequest); - if(ocspSingleResponse) { - CFArrayRef singleResponseSCTs = SecOCSPSingleResponseCopySCTs(ocspSingleResponse); - if(singleResponseSCTs) { - CFArrayAppendArray(SCTs, singleResponseSCTs, CFRangeMake(0, CFArrayGetCount(singleResponseSCTs))); - CFRelease(singleResponseSCTs); - } - SecOCSPSingleResponseDestroy(ocspSingleResponse); - } - } - if(ocspResponse) SecOCSPResponseFinalize(ocspResponse); - }); - - if(CFArrayGetCount(SCTs)==0) { - CFReleaseNull(SCTs); - } - -out: - CFReleaseSafe(ocspResponsesData); - if(ocspRequest) - SecOCSPRequestFinalize(ocspRequest); - - return SCTs; -} - -static void SecPolicyCheckCT(SecPVCRef pvc) -{ - SecCertificateRef leafCert = SecPVCGetCertificateAtIndex(pvc, 0); - CFArrayRef embeddedScts = SecCertificateCopySignedCertificateTimestamps(leafCert); - CFArrayRef builderScts = SecPathBuilderCopySignedCertificateTimestamps(pvc->builder); - CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder); - CFArrayRef ocspScts = copy_ocsp_scts(pvc); - CFDataRef precertEntry = copy_precert_entry_from_chain(pvc); - CFDataRef x509Entry = copy_x509_entry_from_chain(pvc); - __block uint32_t trustedSCTCount = 0; - __block CFAbsoluteTime issuanceTime = SecPVCGetVerifyTime(pvc); - __block CFAbsoluteTime certExpiry = SecCertificateNotValidAfter(leafCert); - TA_CTFailureReason failureReason = TA_CTNoFailure; - - if (!trustedLogs) { - SecOTAPKIRef otapkiref = SecOTAPKICopyCurrentOTAPKIRef(); - trustedLogs = SecOTAPKICopyTrustedCTLogs(otapkiref); - CFReleaseSafe(otapkiref); - } - - // This eventually contain list of logs who validated the SCT. - CFMutableDictionaryRef currentLogsValidatingScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFMutableDictionaryRef logsValidatingEmbeddedScts = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - uint64_t vt = TimestampFromCFAbsoluteTime(SecPVCGetVerifyTime(pvc)); - - __block bool at_least_one_currently_valid_external = 0; - __block bool at_least_one_currently_valid_embedded = 0; - __block bool unknown_log = 0; - __block bool disqualified_log = 0; - - require(logsValidatingEmbeddedScts, out); - require(currentLogsValidatingScts, out); - - /* Skip if there are no SCTs. */ - bool no_scts = (embeddedScts && CFArrayGetCount(embeddedScts) > 0) || - (builderScts && CFArrayGetCount(builderScts) > 0) || - (ocspScts && CFArrayGetCount(ocspScts) > 0); - require_action_quiet(no_scts, out, - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder); - if (analytics) { - analytics->ct_failure_reason = TA_CTNoSCTs; - } - ); - - if(trustedLogs && CFDictionaryGetCount(trustedLogs) > 0) { // Don't bother trying to validate SCTs if we don't have any trusted logs. - if(embeddedScts && precertEntry) { // Don't bother if we could not get the precert. - CFArrayForEach(embeddedScts, ^(const void *value){ - CFAbsoluteTime sct_at; - CFDictionaryRef log = getSCTValidatingLog(value, 1, precertEntry, vt, certExpiry, trustedLogs, &sct_at); - if(log) { - addValidatingLog(logsValidatingEmbeddedScts, log, sct_at); - if(!CFDictionaryContainsKey(log, kSecCTRetirementDateKey)) { - addValidatingLog(currentLogsValidatingScts, log, sct_at); - at_least_one_currently_valid_embedded = true; - trustedSCTCount++; - } else { - disqualified_log = true; - } - } else { - unknown_log = true; - } - }); - } - - if(builderScts && x509Entry) { // Don't bother if we could not get the cert. - CFArrayForEach(builderScts, ^(const void *value){ - CFAbsoluteTime sct_at; - CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, certExpiry, trustedLogs, &sct_at); - if(log) { - addValidatingLog(currentLogsValidatingScts, log, sct_at); - at_least_one_currently_valid_external = true; - trustedSCTCount++; - } else { - unknown_log = true; - } - }); - } - - if(ocspScts && x509Entry) { - CFArrayForEach(ocspScts, ^(const void *value){ - CFAbsoluteTime sct_at; - CFDictionaryRef log = getSCTValidatingLog(value, 0, x509Entry, vt, certExpiry, trustedLogs, &sct_at); - if(log) { - addValidatingLog(currentLogsValidatingScts, log, sct_at); - at_least_one_currently_valid_external = true; - trustedSCTCount++; - } else { - unknown_log = true; - } - }); - } - } else { - failureReason = TA_CTMissingLogs; - } - - - /* We now have 2 sets of logs that validated those SCTS, count them and make a final decision. - - Current Policy: - is_ct = (A1 AND A2) OR (B1 AND B2). - - A1: embedded SCTs from 2+ to 5+ logs valid at issuance time - A2: At least one embedded SCT from a currently valid log. - - B1: SCTs from 2 currently valid logs (from any source) - B2: At least 1 external SCT from a currently valid log. - - */ - - bool hasValidExternalSCT = (at_least_one_currently_valid_external && CFDictionaryGetCount(currentLogsValidatingScts)>=2); - bool hasValidEmbeddedSCT = (at_least_one_currently_valid_embedded); - SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder); - SecCertificatePathVCSetIsCT(path, false); - - if (hasValidEmbeddedSCT) { - /* Calculate issuance time based on timestamp of SCTs from current logs */ - CFDictionaryForEach(currentLogsValidatingScts, ^(const void *key, const void *value) { - CFDictionaryRef log = key; - if(!CFDictionaryContainsKey(log, kSecCTRetirementDateKey)) { - // Log is still qualified - CFDateRef ts = (CFDateRef) value; - CFAbsoluteTime timestamp = CFDateGetAbsoluteTime(ts); - if(timestamp < issuanceTime) { - issuanceTime = timestamp; - } - } - }); - SecCertificatePathVCSetIssuanceTime(path, issuanceTime); - } - if (hasValidExternalSCT) { - /* Note: since external SCT validates this cert, we do not need to - override issuance time here. If the cert also has a valid embedded - SCT, issuanceTime will be calculated and set in the block above. */ - SecCertificatePathVCSetIsCT(path, true); - } else if (hasValidEmbeddedSCT) { - __block int lifetime; // in Months - __block unsigned once_or_current_qualified_embedded = 0; - - /* Count Logs */ - __block bool failed_once_check = false; - CFDictionaryForEach(logsValidatingEmbeddedScts, ^(const void *key, const void *value) { - CFDictionaryRef log = key; - CFDateRef ts = value; - CFDateRef expiry = CFDictionaryGetValue(log, kSecCTRetirementDateKey); - if (expiry == NULL) { // Currently qualified OR - once_or_current_qualified_embedded++; - } else if (CFDateCompare(ts, expiry, NULL) == kCFCompareLessThan && // Once qualified. That is, qualified at the time of SCT AND - issuanceTime < CFDateGetAbsoluteTime(expiry)) { // at the time of issuance.) - once_or_current_qualified_embedded++; - trustedSCTCount++; - } else { - failed_once_check = true; - } - }); - - SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { - int _lifetime; - CFCalendarGetComponentDifference(zuluCalendar, - SecCertificateNotValidBefore(leafCert), - SecCertificateNotValidAfter(leafCert), - 0, "M", &_lifetime); - lifetime = _lifetime; - }); - - unsigned requiredEmbeddedSctsCount; - - if (lifetime < 15) { - requiredEmbeddedSctsCount = 2; - } else if (lifetime <= 27) { - requiredEmbeddedSctsCount = 3; - } else if (lifetime <= 39) { - requiredEmbeddedSctsCount = 4; - } else { - requiredEmbeddedSctsCount = 5; - } - - if(once_or_current_qualified_embedded >= requiredEmbeddedSctsCount){ - SecCertificatePathVCSetIsCT(path, true); - } else { - /* Not enough "once or currently qualified" SCTs */ - if (failed_once_check) { - failureReason = TA_CTEmbeddedNotEnoughDisqualified; - } else if (unknown_log) { - failureReason = TA_CTEmbeddedNotEnoughUnknown; - } else { - failureReason = TA_CTEmbeddedNotEnough; - } - } - } else if (!at_least_one_currently_valid_embedded && !at_least_one_currently_valid_external) { - /* No currently valid SCTs */ - if (disqualified_log) { - failureReason = TA_CTNoCurrentSCTsDisqualifiedLog; - } else if (unknown_log) { - failureReason = TA_CTNoCurrentSCTsUnknownLog; - } - } else if (at_least_one_currently_valid_external) { - /* One presented current SCT but failed total current check */ - if (disqualified_log) { - failureReason = TA_CTPresentedNotEnoughDisqualified; - } else if (unknown_log) { - failureReason = TA_CTPresentedNotEnoughUnknown; - } else { - failureReason = TA_CTPresentedNotEnough; - } - } - - /* Record analytics data for CT */ - TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder); - require_quiet(analytics, out); - uint32_t sctCount = 0; - /* Count the total number of SCTs we found and report where we got them */ - if (embeddedScts && CFArrayGetCount(embeddedScts) > 0) { - analytics->sct_sources |= TA_SCTEmbedded; - sctCount += CFArrayGetCount(embeddedScts); - } - if (builderScts && CFArrayGetCount(builderScts) > 0) { - analytics->sct_sources |= TA_SCT_TLS; - sctCount += CFArrayGetCount(builderScts); - } - if (ocspScts && CFArrayGetCount(ocspScts) > 0) { - analytics->sct_sources |= TA_SCT_OCSP; - sctCount += CFArrayGetCount(ocspScts); - } - /* Report how many of those SCTs were once or currently qualified */ - analytics->number_trusted_scts = trustedSCTCount; - /* Report how many SCTs we got */ - analytics->number_scts = sctCount; - /* Why we failed */ - analytics->ct_failure_reason = failureReason; - /* Only one current SCT -- close to failure */ - if (CFDictionaryGetCount(currentLogsValidatingScts) == 1) { - analytics->ct_one_current = true; - } -out: - CFReleaseSafe(logsValidatingEmbeddedScts); - CFReleaseSafe(currentLogsValidatingScts); - CFReleaseSafe(builderScts); - CFReleaseSafe(embeddedScts); - CFReleaseSafe(ocspScts); - CFReleaseSafe(precertEntry); - CFReleaseSafe(trustedLogs); - CFReleaseSafe(x509Entry); -} - static bool checkPolicyOidData(SecPVCRef pvc, CFDataRef oid) { CFIndex ix, count = SecPVCGetCertificateCount(pvc); DERItem key_value; @@ -2622,6 +1998,21 @@ static void SecPolicyCheckNotCA(SecPVCRef pvc, CFStringRef key) { } } +static void SecPolicyCheckNonTlsCTRequired(SecPVCRef pvc, CFStringRef key) { + // Skip if kill switch enabled or log list not updated + SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef(); + CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder); + if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchNonTLSCT) && + (SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs)) { + // Check CT against the non-TLS log list + if (!SecPolicyCheckNonTlsCT(pvc)) { + SecPVCSetResult(pvc, key, 0, kCFBooleanFalse); + } + } + CFReleaseNull(otaref); + CFReleaseNull(trustedLogs); +} + void SecPolicyServerInitialize(void) { gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); @@ -2712,15 +2103,15 @@ SecPolicyRef SecPVCGetPolicy(SecPVCRef pvc) { return (SecPolicyRef)CFArrayGetValueAtIndex(pvc->policies, pvc->policyIX); } -static CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { +CFIndex SecPVCGetCertificateCount(SecPVCRef pvc) { return SecPathBuilderGetCertificateCount(pvc->builder); } -static SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { +SecCertificateRef SecPVCGetCertificateAtIndex(SecPVCRef pvc, CFIndex ix) { return SecPathBuilderGetCertificateAtIndex(pvc->builder, ix); } -static CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { +CFAbsoluteTime SecPVCGetVerifyTime(SecPVCRef pvc) { return SecPathBuilderGetVerifyTime(pvc->builder); }