* SecPolicyServer.c - Engine for evaluating certificate paths against trust policies.
*/
-#include "trust/trustd/SecPolicyServer.h"
-#include <Security/SecPolicyInternal.h>
-#include <Security/SecPolicyPriv.h>
-#include <Security/SecTask.h>
-#include "trust/trustd/policytree.h"
-#include "trust/trustd/nameconstraints.h"
-#include <CoreFoundation/CFTimeZone.h>
+#include <AssertMacros.h>
#include <wctype.h>
-#include <libDER/oids.h>
+#include <asl.h>
+
+#include <CommonCrypto/CommonDigest.h>
+#include <CoreFoundation/CFTimeZone.h>
#include <CoreFoundation/CFNumber.h>
-#include <Security/SecCertificateInternal.h>
-#include <AssertMacros.h>
+#include <sys/codesign.h>
+#include <libDER/DER_CertCrl.h>
+#include <libDER/DER_Encode.h>
+#include <libDER/asn1Types.h>
+#include <libDER/oids.h>
+#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+
+#include <utilities/array_size.h>
+#include <utilities/SecCFWrappers.h>
+#include <utilities/SecAppleAnchorPriv.h>
#include <utilities/debugging.h>
#include <utilities/SecInternalReleasePriv.h>
#include <security_asn1/SecAsn1Coder.h>
#include <security_asn1/ocspTemplates.h>
#include <security_asn1/oidsalg.h>
#include <security_asn1/oidsocsp.h>
-#include <CommonCrypto/CommonDigest.h>
+#include <Security/SecPolicyInternal.h>
+#include <Security/SecPolicyPriv.h>
+#include <Security/SecTask.h>
+#include <Security/SecCertificateInternal.h>
#include <Security/SecFramework.h>
#include <Security/SecPolicyInternal.h>
#include <Security/SecTrustPriv.h>
#include <Security/SecTrustSettingsPriv.h>
#include <Security/SecInternal.h>
#include <Security/SecKeyPriv.h>
-#include <Security/SecTask.h>
-#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
-#include <asl.h>
+
+#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"
#include "trust/trustd/SecCertificateSource.h"
#include "trust/trustd/SecOCSPResponse.h"
#include "trust/trustd/SecTrustStoreServer.h"
-#include <utilities/array_size.h>
-#include <utilities/SecCFWrappers.h>
-#include <utilities/SecAppleAnchorPriv.h>
-#include "OTATrustUtilities.h"
-#include "personalization.h"
-#include <sys/codesign.h>
+#include "trust/trustd/OTATrustUtilities.h"
+#include "trust/trustd/personalization.h"
+#include "trust/trustd/CertificateTransparency.h"
#if !TARGET_OS_IPHONE
#include <Security/SecTaskPriv.h>
****************** 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;
*/
}
-
-/*
- * 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 <Security/SecureTransportPriv.h>
-
-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 <libDER/DER_CertCrl.h>
-#include <libDER/DER_Encode.h>
-#include <libDER/asn1Types.h>
-
-
-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;
}
}
+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);
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);
}