root_cgo_darwin.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // +build cgo,!arm,!arm64,!ios
  5. package x509
  6. /*
  7. #cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
  8. #cgo LDFLAGS: -framework CoreFoundation -framework Security
  9. #include <errno.h>
  10. #include <sys/sysctl.h>
  11. #include <CoreFoundation/CoreFoundation.h>
  12. #include <Security/Security.h>
  13. // FetchPEMRootsCTX509_MountainLion is the version of FetchPEMRoots from Go 1.6
  14. // which still works on OS X 10.8 (Mountain Lion).
  15. // It lacks support for admin & user cert domains.
  16. // See golang.org/issue/16473
  17. int FetchPEMRootsCTX509_MountainLion(CFDataRef *pemRoots) {
  18. if (pemRoots == NULL) {
  19. return -1;
  20. }
  21. CFArrayRef certs = NULL;
  22. OSStatus err = SecTrustCopyAnchorCertificates(&certs);
  23. if (err != noErr) {
  24. return -1;
  25. }
  26. CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
  27. int i, ncerts = CFArrayGetCount(certs);
  28. for (i = 0; i < ncerts; i++) {
  29. CFDataRef data = NULL;
  30. SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
  31. if (cert == NULL) {
  32. continue;
  33. }
  34. // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
  35. // Once we support weak imports via cgo we should prefer that, and fall back to this
  36. // for older systems.
  37. err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
  38. if (err != noErr) {
  39. continue;
  40. }
  41. if (data != NULL) {
  42. CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
  43. CFRelease(data);
  44. }
  45. }
  46. CFRelease(certs);
  47. *pemRoots = combinedData;
  48. return 0;
  49. }
  50. // useOldCodeCTX509 reports whether the running machine is OS X 10.8 Mountain Lion
  51. // or older. We only support Mountain Lion and higher, but we'll at least try our
  52. // best on older machines and continue to use the old code path.
  53. //
  54. // See golang.org/issue/16473
  55. int useOldCodeCTX509() {
  56. char str[256];
  57. size_t size = sizeof(str);
  58. memset(str, 0, size);
  59. sysctlbyname("kern.osrelease", str, &size, NULL, 0);
  60. // OS X 10.8 is osrelease "12.*", 10.7 is 11.*, 10.6 is 10.*.
  61. // We never supported things before that.
  62. return memcmp(str, "12.", 3) == 0 || memcmp(str, "11.", 3) == 0 || memcmp(str, "10.", 3) == 0;
  63. }
  64. // FetchPEMRootsCTX509 fetches the system's list of trusted X.509 root certificates.
  65. //
  66. // On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
  67. // certificates of the system. On failure, the function returns -1.
  68. // Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots.
  69. //
  70. // Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
  71. // be released (using CFRelease) after we've consumed its content.
  72. int FetchPEMRootsCTX509(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
  73. if (useOldCodeCTX509()) {
  74. return FetchPEMRootsCTX509_MountainLion(pemRoots);
  75. }
  76. // Get certificates from all domains, not just System, this lets
  77. // the user add CAs to their "login" keychain, and Admins to add
  78. // to the "System" keychain
  79. SecTrustSettingsDomain domains[] = { kSecTrustSettingsDomainSystem,
  80. kSecTrustSettingsDomainAdmin,
  81. kSecTrustSettingsDomainUser };
  82. int numDomains = sizeof(domains)/sizeof(SecTrustSettingsDomain);
  83. if (pemRoots == NULL) {
  84. return -1;
  85. }
  86. // kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
  87. // but the Go linker's internal linking mode can't handle CFSTR relocations.
  88. // Create our own dynamic string instead and release it below.
  89. CFStringRef policy = CFStringCreateWithCString(NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
  90. CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
  91. CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
  92. for (int i = 0; i < numDomains; i++) {
  93. CFArrayRef certs = NULL;
  94. OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
  95. if (err != noErr) {
  96. continue;
  97. }
  98. CFIndex numCerts = CFArrayGetCount(certs);
  99. for (int j = 0; j < numCerts; j++) {
  100. CFDataRef data = NULL;
  101. CFErrorRef errRef = NULL;
  102. CFArrayRef trustSettings = NULL;
  103. SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
  104. if (cert == NULL) {
  105. continue;
  106. }
  107. // We only want trusted certs.
  108. int untrusted = 0;
  109. int trustAsRoot = 0;
  110. int trustRoot = 0;
  111. if (i == 0) {
  112. trustAsRoot = 1;
  113. } else {
  114. // Certs found in the system domain are always trusted. If the user
  115. // configures "Never Trust" on such a cert, it will also be found in the
  116. // admin or user domain, causing it to be added to untrustedPemRoots. The
  117. // Go code will then clean this up.
  118. // Trust may be stored in any of the domains. According to Apple's
  119. // SecTrustServer.c, "user trust settings overrule admin trust settings",
  120. // so take the last trust settings array we find.
  121. // Skip the system domain since it is always trusted.
  122. for (int k = i; k < numDomains; k++) {
  123. CFArrayRef domainTrustSettings = NULL;
  124. err = SecTrustSettingsCopyTrustSettings(cert, domains[k], &domainTrustSettings);
  125. if (err == errSecSuccess && domainTrustSettings != NULL) {
  126. if (trustSettings) {
  127. CFRelease(trustSettings);
  128. }
  129. trustSettings = domainTrustSettings;
  130. }
  131. }
  132. if (trustSettings == NULL) {
  133. // "this certificate must be verified to a known trusted certificate"; aka not a root.
  134. continue;
  135. }
  136. for (CFIndex k = 0; k < CFArrayGetCount(trustSettings); k++) {
  137. CFNumberRef cfNum;
  138. CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, k);
  139. if (CFDictionaryGetValueIfPresent(tSetting, policy, (const void**)&cfNum)){
  140. SInt32 result = 0;
  141. CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
  142. // TODO: The rest of the dictionary specifies conditions for evaluation.
  143. if (result == kSecTrustSettingsResultDeny) {
  144. untrusted = 1;
  145. } else if (result == kSecTrustSettingsResultTrustAsRoot) {
  146. trustAsRoot = 1;
  147. } else if (result == kSecTrustSettingsResultTrustRoot) {
  148. trustRoot = 1;
  149. }
  150. }
  151. }
  152. CFRelease(trustSettings);
  153. }
  154. if (trustRoot) {
  155. // We only want to add Root CAs, so make sure Subject and Issuer Name match
  156. CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
  157. if (errRef != NULL) {
  158. CFRelease(errRef);
  159. continue;
  160. }
  161. CFDataRef issuerName = SecCertificateCopyNormalizedIssuerContent(cert, &errRef);
  162. if (errRef != NULL) {
  163. CFRelease(subjectName);
  164. CFRelease(errRef);
  165. continue;
  166. }
  167. Boolean equal = CFEqual(subjectName, issuerName);
  168. CFRelease(subjectName);
  169. CFRelease(issuerName);
  170. if (!equal) {
  171. continue;
  172. }
  173. }
  174. // Note: SecKeychainItemExport is deprecated as of 10.7 in favor of SecItemExport.
  175. // Once we support weak imports via cgo we should prefer that, and fall back to this
  176. // for older systems.
  177. err = SecKeychainItemExport(cert, kSecFormatX509Cert, kSecItemPemArmour, NULL, &data);
  178. if (err != noErr) {
  179. continue;
  180. }
  181. if (data != NULL) {
  182. if (!trustRoot && !trustAsRoot) {
  183. untrusted = 1;
  184. }
  185. CFMutableDataRef appendTo = untrusted ? combinedUntrustedData : combinedData;
  186. CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
  187. CFRelease(data);
  188. }
  189. }
  190. CFRelease(certs);
  191. }
  192. CFRelease(policy);
  193. *pemRoots = combinedData;
  194. *untrustedPemRoots = combinedUntrustedData;
  195. return 0;
  196. }
  197. */
  198. import "C"
  199. import (
  200. "errors"
  201. "unsafe"
  202. )
  203. func loadSystemRoots() (*CertPool, error) {
  204. roots := NewCertPool()
  205. var data C.CFDataRef
  206. setNilCFRef(&data)
  207. var untrustedData C.CFDataRef
  208. setNilCFRef(&untrustedData)
  209. err := C.FetchPEMRootsCTX509(&data, &untrustedData)
  210. if err == -1 {
  211. // TODO: better error message
  212. return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
  213. }
  214. defer C.CFRelease(C.CFTypeRef(data))
  215. buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
  216. roots.AppendCertsFromPEM(buf)
  217. if isNilCFRef(untrustedData) {
  218. return roots, nil
  219. }
  220. defer C.CFRelease(C.CFTypeRef(untrustedData))
  221. buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData)))
  222. untrustedRoots := NewCertPool()
  223. untrustedRoots.AppendCertsFromPEM(buf)
  224. trustedRoots := NewCertPool()
  225. for _, c := range roots.certs {
  226. if !untrustedRoots.contains(c) {
  227. trustedRoots.AddCert(c)
  228. }
  229. }
  230. return trustedRoots, nil
  231. }