14

Is there a way to set up an OpenSSL context (SSL_CTX) with a reasonable set of trusted CA certificates without distributing them myself? I don't want the responsibility of keeping them up to date. IMO any modern operating system should provide "get me the trusted CA certs" as a service, but I don't know if that's actually the case.

I don't mind writing this code three times (once for Windows, once for Mac OS X, and once for Linux), but I'd prefer to cap it at that. In particular, I'd rather not try to write code that snoops around looking for what browsers are installed and trying to extract their trusted certificates. (Apparently it's easy to get this very wrong.)

The answer for recent versions of Linux seems to be to call SSL_CTX_load_verify_locations with /etc/ssl/certs/ca-certificates.crt (if that file exists).

Are there simple answers for Windows and Mac OS X?

Ryan Culpepper
  • 10,495
  • 4
  • 31
  • 30

3 Answers3

12

Here's what I ended up doing:

On Windows: get the certificates from the Windows "ROOT" certificate store using CertOpenSystemStore, loop over them using CertEnumCertificatesInStore, grab the X509-encoded raw certificate from the pbCertEncoded field of the CERT_CONTEXT, create an OpenSSL X509 structure using d2i_X509, and add it to the OpenSSL certificate store using X509_STORE_add_cert. The Windows functions are all available from crypt32.dll.

On Mac OS X: get the certificates from the "/System/Library/Keychains/SystemRootCertificates.keychain" keychain using SecKeychainOpen, create an iterator for the certificates in the keychain using SecKeychainSearchCreateFromAttributes, iterate using SecKeychainSearchCopyNext, get the raw X509 certificate using SecItemExport, create an OpenSSL certificate using d2i_X509, and add it to the OpenSSL store using X509_STORE_add_cert. The Mac functions are available from /Systems/Library/Frameworks/Security.framework/Security.

A better approach might be to create an OpenSSL X509_STORE with a callback that uses OS functions to verify an individual root cert, rather than copying all of them over, but I haven't tried that.

Ryan Culpepper
  • 10,495
  • 4
  • 31
  • 30
  • @proteneer, the code is now part of the Racket openssl library here: https://github.com/plt/racket/tree/master/racket/collects/openssl/private – Ryan Culpepper Jan 26 '14 at 16:02
  • 1
    The Windows code described above is available in actual code here: https://curl.haxx.se/mail/meet-2017-03/0030.html – mamacdon Feb 17 '20 at 00:58
  • Update: On Mac OS, it seems like it might be better to use `SecTrustCopyAnchorCertificates` rather than opening the system keychain and iterating through it. The remaining steps are the same. – Ryan Culpepper Apr 11 '22 at 13:30
6

On OS X, you can get information on the certificates trusted by the user from the user's Keychain. Here is a link containing some very good information on collecting that info using Cocoa:

Get Certificates in Keychain

If Cocoa is not an ok dependency for your needs, and you want to do everything straight from the command line, you could use the certtool utility- see man certtool and other online documentation to learn about it. To list all certificates in the user's login keychain, you might do:

certtool y k=login.keychain

Or to get a list of the built-in trusted system roots:

certtool y k=/System/Library/Keychains/SystemRootCertificates.keychain

and maybe

certtool y k=/System/Library/Keychains/SystemCACertificates.keychain

I'm sure there are other ways to get at that information using system interfaces as well.

On the Linux side, yes, /etc/ssl/certs/ca-certificates.crt is the right way to go. That file will exist on Debian derivatives (inc. Ubuntu variants) when the ca-certificates package is installed, and I'm not sure how to get it there properly on redhat-based systems.

Community
  • 1
  • 1
the paul
  • 8,972
  • 1
  • 36
  • 53
  • Do you know how `certtool` behaves for certificates that are explicitly flagged as "never trust", though? – Bruno Apr 26 '12 at 20:40
  • I don't think certtool will show anything regarding trust levels; you'd want to query for trustiness using a different mechanism. Try `man security` for one good way, if you're really into using the command line tools for this. – the paul Apr 26 '12 at 21:19
  • 1
    See also MacPorts' certsync utility (https://trac.macports.org/browser/trunk/dports/security/certsync/#files, the actual code is in `files/certsync.m`), which also exports the trusted roots into a file and does pay attention to the trust flags (by not exporting them). – neverpanic Jul 03 '15 at 12:45
5

You could use curl's script that converts the list from Mozilla (from Curl's maintainer's answer). According to its code, it seems to check whether the certificate is trusted or not before including it.

Community
  • 1
  • 1
Bruno
  • 119,590
  • 31
  • 270
  • 376