Ignore:
Timestamp:
Mar 16, 2014, 4:53:32 PM (5 years ago)
Author:
landonf@…
Message:

Validate self-trust of certificates prior to export.

This handles the case where the certificate, though trusted, will not actually be useable for validation; eg, the certificate is expired.

Issue: #42718

Location:
trunk/dports/security/certsync
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/dports/security/certsync/Portfile

    r115031 r117895  
    44
    55name                    certsync
    6 version                 1.0.6
    7 revision                3
     6version                 1.0.7
    87categories              security
    98conflicts               curl-ca-bundle
  • trunk/dports/security/certsync/files/certsync.m

    r115009 r117895  
    9797
    9898/**
     99 * Verify that the root certificate trusts itself; this filters out certificates that
     100 * are still marked as trusted by the OS, but are expired or otherwise unusable.
     101 */
     102static BOOL ValidateSelfTrust (SecCertificateRef cert) {
     103    OSStatus err;
     104
     105    /* Create a new trust evaluation instance */
     106    SecTrustRef trust;
     107    {
     108        SecPolicyRef policy = SecPolicyCreateBasicX509();
     109        if ((err = SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust)) != errSecSuccess) {
     110            /* Shouldn't happen */
     111            nsfprintf(stderr, @"Failed to create SecTrustRef: %d\n", err);
     112            CFRelease(policy);
     113            return NO;
     114        }
     115        CFRelease(policy);
     116    }
     117   
     118    /* Set this certificate as the only (self-)anchor */
     119    {
     120        CFArrayRef certs = CFArrayCreate(NULL, (const void **) &cert, 1, &kCFTypeArrayCallBacks);
     121        if ((err = SecTrustSetAnchorCertificates(trust, certs)) != errSecSuccess) {
     122            nsfprintf(stderr, @"Failed to set anchor certificates on our SecTrustRef: %d\n", err);
     123            CFRelease(certs);
     124            CFRelease(trust);
     125            return NO;
     126        }
     127        CFRelease(certs);
     128    }
     129   
     130    /* Evaluate the certificate trust */
     131    SecTrustResultType rt;
     132    if ((err = SecTrustEvaluate(trust, &rt)) != errSecSuccess) {
     133        nsfprintf(stderr, @"SecTrustEvaluate() failed: %d\n", err);
     134        CFRelease(trust);
     135    }
     136   
     137    CFRelease(trust);
     138   
     139    /* Check the result */
     140    switch (rt) {
     141        case kSecTrustResultUnspecified:
     142        case kSecTrustResultProceed:
     143            /* Trusted */
     144            return YES;
     145           
     146        default:
     147            /* Untrusted */
     148            return NO;
     149    }
     150}
     151
     152/**
    99153 * Fetch all trusted roots for the given @a domain.
    100154 *
     
    106160static NSArray *certificatesForTrustDomain (SecTrustSettingsDomain domain, NSError **outError) {
    107161    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    108     NSArray *trusted = nil;
     162    NSMutableArray *trusted = nil;
    109163    CFArrayRef certs = nil;
    110164    OSStatus err;
     
    132186   
    133187        /* Extract trusted roots */
    134         NSMutableArray *results = [NSMutableArray arrayWithCapacity: CFArrayGetCount(certs)];
    135         trusted = results;
     188        trusted = [NSMutableArray arrayWithCapacity: CFArrayGetCount(certs)];
    136189       
    137190        NSEnumerator *resultEnumerator = [(NSArray *)certs objectEnumerator];
     
    153206            /* If empty, trust for everything (as per the Security Framework documentation) */
    154207            if (CFArrayGetCount(trustSettings) == 0) {
    155                 [results addObject: certObj];
     208                [trusted addObject: certObj];
    156209            } else {
    157210                /* Otherwise, walk the properties and evaluate the trust settings result */
     
    167220                    /* If a root, add to the result set */
    168221                    if (settingsResult == kSecTrustSettingsResultTrustRoot || settingsResult == kSecTrustSettingsResultTrustAsRoot) {
    169                         [results addObject: certObj];
     222                        [trusted addObject: certObj];
    170223                        break;
    171224                    }
     
    193246
    194247        /* All certs are trusted */
    195         trusted = (NSArray *) certs;
     248        trusted = [[(NSArray *) certs mutableCopy] autorelease];
     249        CFRelease(certs);
     250    }
     251   
     252    /*
     253     * Filter out any trusted certificates that can not actually be used in verification; eg, they are expired.
     254     *
     255     * There are cases where CAs have issued new certificates using identical public keys, and the expired
     256     * and current CA certificates are both included in the list of trusted certificates. In such a case,
     257     * OpenSSL will use either of the two certificates; if that happens to be the expired certificate,
     258     * validation will fail.
     259     *
     260     * This step ensures that we exclude any expired or known-unusable certificates.
     261     *
     262     * We enumerate a copy of the array so that we can safely modify the original during enumeration.
     263     */
     264    NSEnumerator *trustedEnumerator = [[[trusted copy] autorelease] objectEnumerator];
     265    id certObj;
     266    while ((certObj = [trustedEnumerator nextObject]) != nil) {
     267        /* If self-trust validation fails, the certificate is expired or otherwise not useable */
     268        if (!ValidateSelfTrust((SecCertificateRef) certObj)) {
     269            [trusted removeObject: certObj];
     270        }
    196271    }
    197272   
Note: See TracChangeset for help on using the changeset viewer.