[117895] trunk/dports/security/certsync

landonf at macports.org landonf at macports.org
Sun Mar 16 09:53:32 PDT 2014


Revision: 117895
          https://trac.macports.org/changeset/117895
Author:   landonf at macports.org
Date:     2014-03-16 09:53:32 -0700 (Sun, 16 Mar 2014)
Log 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

Modified Paths:
--------------
    trunk/dports/security/certsync/Portfile
    trunk/dports/security/certsync/files/certsync.m

Modified: trunk/dports/security/certsync/Portfile
===================================================================
--- trunk/dports/security/certsync/Portfile	2014-03-16 16:36:45 UTC (rev 117894)
+++ trunk/dports/security/certsync/Portfile	2014-03-16 16:53:32 UTC (rev 117895)
@@ -3,8 +3,7 @@
 PortSystem		1.0
 
 name			certsync
-version			1.0.6
-revision		3
+version			1.0.7
 categories		security
 conflicts		curl-ca-bundle
 maintainers		landonf openmaintainer

Modified: trunk/dports/security/certsync/files/certsync.m
===================================================================
--- trunk/dports/security/certsync/files/certsync.m	2014-03-16 16:36:45 UTC (rev 117894)
+++ trunk/dports/security/certsync/files/certsync.m	2014-03-16 16:53:32 UTC (rev 117895)
@@ -96,6 +96,60 @@
 }
 
 /**
+ * Verify that the root certificate trusts itself; this filters out certificates that
+ * are still marked as trusted by the OS, but are expired or otherwise unusable.
+ */
+static BOOL ValidateSelfTrust (SecCertificateRef cert) {
+    OSStatus err;
+
+    /* Create a new trust evaluation instance */
+    SecTrustRef trust;
+    {
+        SecPolicyRef policy = SecPolicyCreateBasicX509();
+        if ((err = SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust)) != errSecSuccess) {
+            /* Shouldn't happen */
+            nsfprintf(stderr, @"Failed to create SecTrustRef: %d\n", err);
+            CFRelease(policy);
+            return NO;
+        }
+        CFRelease(policy);
+    }
+    
+    /* Set this certificate as the only (self-)anchor */
+    {
+        CFArrayRef certs = CFArrayCreate(NULL, (const void **) &cert, 1, &kCFTypeArrayCallBacks);
+        if ((err = SecTrustSetAnchorCertificates(trust, certs)) != errSecSuccess) {
+            nsfprintf(stderr, @"Failed to set anchor certificates on our SecTrustRef: %d\n", err);
+            CFRelease(certs);
+            CFRelease(trust);
+            return NO;
+        }
+        CFRelease(certs);
+    }
+    
+    /* Evaluate the certificate trust */
+    SecTrustResultType rt;
+    if ((err = SecTrustEvaluate(trust, &rt)) != errSecSuccess) {
+        nsfprintf(stderr, @"SecTrustEvaluate() failed: %d\n", err);
+        CFRelease(trust);
+    }
+    
+    CFRelease(trust);
+    
+    /* Check the result */
+    switch (rt) {
+        case kSecTrustResultUnspecified:
+        case kSecTrustResultProceed:
+            /* Trusted */
+            return YES;
+            
+        default:
+            /* Untrusted */
+            return NO;
+    }
+}
+
+/**
  * Fetch all trusted roots for the given @a domain.
  *
  * @param domain The trust domain to query.
@@ -105,7 +159,7 @@
  */
 static NSArray *certificatesForTrustDomain (SecTrustSettingsDomain domain, NSError **outError) {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-    NSArray *trusted = nil;
+    NSMutableArray *trusted = nil;
     CFArrayRef certs = nil;
     OSStatus err;
     
@@ -131,8 +185,7 @@
         }
     
         /* Extract trusted roots */
-        NSMutableArray *results = [NSMutableArray arrayWithCapacity: CFArrayGetCount(certs)];
-        trusted = results;
+        trusted = [NSMutableArray arrayWithCapacity: CFArrayGetCount(certs)];
         
         NSEnumerator *resultEnumerator = [(NSArray *)certs objectEnumerator];
         id certObj;
@@ -152,7 +205,7 @@
         
             /* If empty, trust for everything (as per the Security Framework documentation) */
             if (CFArrayGetCount(trustSettings) == 0) {
-                [results addObject: certObj];
+                [trusted addObject: certObj];
             } else {
                 /* Otherwise, walk the properties and evaluate the trust settings result */
                 NSEnumerator *trustEnumerator = [(NSArray *)trustSettings objectEnumerator];
@@ -166,7 +219,7 @@
                 
                     /* If a root, add to the result set */
                     if (settingsResult == kSecTrustSettingsResultTrustRoot || settingsResult == kSecTrustSettingsResultTrustAsRoot) {
-                        [results addObject: certObj];
+                        [trusted addObject: certObj];
                         break;
                     }
                 }
@@ -192,9 +245,31 @@
         }
 
         /* All certs are trusted */
-        trusted = (NSArray *) certs;
+        trusted = [[(NSArray *) certs mutableCopy] autorelease];
+        CFRelease(certs);
     }
     
+    /*
+     * Filter out any trusted certificates that can not actually be used in verification; eg, they are expired.
+     *
+     * There are cases where CAs have issued new certificates using identical public keys, and the expired
+     * and current CA certificates are both included in the list of trusted certificates. In such a case,
+     * OpenSSL will use either of the two certificates; if that happens to be the expired certificate,
+     * validation will fail.
+     *
+     * This step ensures that we exclude any expired or known-unusable certificates.
+     *
+     * We enumerate a copy of the array so that we can safely modify the original during enumeration.
+     */
+    NSEnumerator *trustedEnumerator = [[[trusted copy] autorelease] objectEnumerator];
+    id certObj;
+    while ((certObj = [trustedEnumerator nextObject]) != nil) {
+        /* If self-trust validation fails, the certificate is expired or otherwise not useable */
+        if (!ValidateSelfTrust((SecCertificateRef) certObj)) {
+            [trusted removeObject: certObj];
+        }
+    }
+    
     [trusted retain];
     [pool release];
     return [trusted autorelease];
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20140316/ec48c86e/attachment.html>


More information about the macports-changes mailing list