]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/x509: add Admin & User Keychains to FetchPEMRoots on Darwin
authorLee Hinman <hinman@gmail.com>
Tue, 8 Mar 2016 04:31:31 +0000 (22:31 -0600)
committerRuss Cox <rsc@golang.org>
Wed, 18 May 2016 14:26:59 +0000 (14:26 +0000)
in root_cgo_darwin.go only certificates from the System Domain
were being used in FetchPEMRoots.  This patch adds support for
getting certificates from all three domains (System, Admin,
User).  Also it will only read trusted certificates from those
Keychains.  Because it is possible to trust a non Root certificate,
this patch also adds a checks to see if the Subject and Issuer
name are the same.

Fixes #14514

Change-Id: Ia03936d7a61d1e24e99f31c92f9927ae48b2b494
Reviewed-on: https://go-review.googlesource.com/20351
Reviewed-by: Russ Cox <rsc@golang.org>
src/crypto/x509/root_cgo_darwin.go

index f067cd7cf432fcd134400d569e94c8531a1f0491..0e2fb357ee904034b46e96f8f06094bce2fad5b6 100644 (file)
@@ -21,41 +21,69 @@ package x509
 // Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
 // we've consumed its content.
 int FetchPEMRoots(CFDataRef *pemRoots) {
-       if (pemRoots == NULL) {
-               return -1;
-       }
+       // Get certificates from all domains, not just System, this lets
+       // the user add CAs to their "login" keychain, and Admins to add
+       // to the "System" keychain
+       SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
+                                            kSecTrustSettingsDomainAdmin,
+                                            kSecTrustSettingsDomainUser };
 
-       CFArrayRef certs = NULL;
-       OSStatus err = SecTrustCopyAnchorCertificates(&certs);
-       if (err != noErr) {
+       int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
+       if (pemRoots == NULL) {
                return -1;
        }
 
        CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
-       int i, ncerts = CFArrayGetCount(certs);
-       for (i = 0; i < ncerts; i++) {
-               CFDataRef data = NULL;
-               SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
-               if (cert == NULL) {
-                       continue;
-               }
-
-               // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
-               // Once we support weak imports via cgo we should prefer that, and fall back to this
-               // for older systems.
-               err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+       for (int i = 0; i < numDomains; i++) {
+               CFArrayRef certs = NULL;
+               // Only get certificates from domain that are trusted
+               OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
                if (err != noErr) {
                        continue;
                }
 
-               if (data != NULL) {
-                       CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
-                       CFRelease(data);
-               }
-       }
+               int numCerts = CFArrayGetCount(certs);
+               for (int j = 0; j < numCerts; j++) {
+                       CFDataRef data = NULL;
+                       CFErrorRef errRef = NULL;
+                       SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
+                       if (cert == NULL) {
+                               continue;
+                       }
+                       // We only want to add Root CAs, so make sure Subject and Issuer Name match
+                       CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
+                       if (errRef != NULL) {
+                               CFRelease(errRef);
+                               continue;
+                       }
+                       CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
+                       if (errRef != NULL) {
+                               CFRelease(subjectName);
+                               CFRelease(errRef);
+                               continue;
+                       }
+                       Boolean equal = CFEqual(subjectName, issuerName);
+                       CFRelease(subjectName);
+                       CFRelease(issuerName);
+                       if (!equal) {
+                               continue;
+                       }
 
-       CFRelease(certs);
+                       // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
+                       // Once we support weak imports via cgo we should prefer that, and fall back to this
+                       // for older systems.
+                       err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
+                       if (err != noErr) {
+                               continue;
+                       }
 
+                       if (data != NULL) {
+                               CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
+                               CFRelease(data);
+                       }
+               }
+               CFRelease(certs);
+       }
        *pemRoots = combinedData;
        return 0;
 }