tl;dr
I’m taking a page from the Elixir community’s playbook here, the Ca_store module includes an up-to-date public certificate chain from a generally trustworthy source (eg. Mozilla) that we’ll update via CI and publish automatically to opam periodically.
How to use it
Easy, just opam install castore and in your dune-project make sure to use (castore (>= "0.0.0")) so you automatically upgrade to the latest certificate.
Now you can use it with ocaml-tls and when you need that .pem file you can feed it the contents of Ca_store.pem.
Why we did this
I was building an HTTP client for Riot and realized that to support TLS I’d need to either have custom certificates or bring in ca-store and let it resolve them from the system.
The Elixir community’s approach to this is a lot simpler.
What’s missing/next
The latest .pem file was updated on Dec 12th and I need to build the scheduled CI workflow that’ll update it / publish the lib, so if you’re into crypto (maybe i can nerdsnipe @hannes?) or ci (@ulrikstrid?) then ping me
You can use it like any other .pem file you’d normally read from disk, but if you want some code, in that HTTP client we’re using some code we copied over from ca-certs to parse this .pem file into something we can use with X509.
I’m considering doing this parsing and conversion in the repo’s CI, so the outputs would be available in Ca_store.cas so you can run:
let cas = List.map X509.Authenticator.decode_pem Ca_store.cas in
let authenticator = X509.Authenticator.chain_of_trust ~time cas in
let tls_config = Tls.Config.client ~authenticator () in
(* ... *)
I spent a little time consolidating that preprocessing code into castore, and 0.0.2 is on its way on opam.
It’ll let you write this:
let decode_pem ca =
let ca = Cstruct.of_string ca in
let cert = X509.Certificate.decode_pem ca in
Result.get_ok cert
in
let cas = List.map decode_pem Ca_store.certificates in
let authenticator = X509.Authenticator.chain_of_trust ~time cas in
let tls_config = Tls.Config.client ~authenticator () in
(* ... *)
Could you elaborate what problem is solved here? How does this save you from using custom certificates in your own application and what is the role of the embedded certificate?
This solves the issue of needing external dependencies to read in a trusted certificate chain for talking to services over SSL.
In this case, if you’re building a client for anything (HTTP, WS, IRC, etc) that needs an SSL handshake, you can give your users a reasonable default without imposing runtime requirements on their application.
The non-use cases here are:
If you want to use custom certificates
If you need a set of certificate/private keys for your server
Reusing the OS-installed certificates
So if you need either of these you should use X509 directly, or ca-certs.
Given that the trusted cert chain is updated fairly frequently I wonder if maybe publishing to opam for every update would be a bit too much churn and maybe it can be set up to send a new release PR once a month or something.