-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Description
Proposal
Go programs currently rely on the operating system to provide CA root certificate information in some sort of certificate system store. There are situations, where no such up-to-date CA root certificates are available like (Docker) containers built FROM scratch
or out of date environments like poorly maintained or no longer updatable systems (e.g. older hardware appliances).
For some environments it is possible for the user of a Go program to add additional CA root certificates via SSL_CERT_FILE
or SSL_CERT_DIR
, but this is not the case for all supported environments (e.g. Windows) and it is definitively not user friendly.
Therefore, it is desirable for Go programs to have some mechanism to directly embed CA root certificate information into the program itself, so that they don't have to rely on system store to provide CA root certificates that may be absent (or out of date).
I make the following assumptions, which I think are reasonable:
- adding the CA root certificates into a program should be optional, as it increases the size of the program by approximately 250K (uncompressed), and most programs run in properly maintained systems with an up-to-date certificate system store
- it should be possible to embed CA root certificates when building an arbitrary program
- it should be possible for a program to always embed CA root certificates without requiring any special build step
- the program should always prefer data from the system if available, as it is likely to be more up to date than that included in the program
- the program should allow to override the preference and force the usage of the embeded data (controled by an environment variable, e.g.
GO_ROOTCERTS_ENABLE
)
Given those assumptions, I propose adding a new package crypto/x509/rootcerts
. Importing this package (as import _ "crypto/x509/rootcerts"
) will cause CA root certificates to be embedded in the program. Also, building with the build tag rootcerts
will force the package to be imported, and therefore will cause CA root certificates to be embedded in the program. The embedded CA root certificates will be used if and when no certificate system store is available (or the user forces the usage of the embedded data).
Source for the CA Root Certificates
I propose to use the Mozilla Included CA Certificate List, more specifically the PEM of Root Certificates in Mozilla's Root Store with the Websites (TLS/SSL) Trust Bit Enabled as the source for the CA root certificates.
The Mozilla Included CA Certificate List is the source for the CA root certificates embeded in the well known products of the Mozilla Foundation like for example Firefox (web browser) or Thunderbird (email client).
In contrast to most of the other software vendors, Mozilla maintains its Included CA Certificate List publicly and distributes it under an open source license (Mozilla Public License Version 2). This is also the reason why most of the Linux distributions, as well as
other free unix derivates and wide spread tools, use this list of CA root certificates as part of their distribution.
Some examples:
- Debian (and its derivates): ca-certificates
- Red Hat / Fedora / CentOS: ca-certificates / ca-certificates
- Alpine Linux: ca-certificates
- FreeBSD: ca_root_nss
- NetBSD: ca-certificates
- curl: cacert.pem
In summary in my opinion it is safe to say that the Mozilla Included CA Certificate List is well established and widely used.
In fact, if a Go program is run on Linux or an other free Unix derivate, chances are high that the root certificates used by the program are already provided by the Mozilla Included CA Certificate List.
Why include into the Go Standard Library
As the sample implementation (link in Annex below) clearly demostrates, that it is possible to write a 3rd party Go package, which achieves the same goal as the proposed package crypto/x509/rootcerts
would. The main difference between a package in the standard library and a 3rd party package is: TRUST.
The root certificates are the top-most certificates in the trust chain and used to ensure the trustworthiness of the certificates signed by them either directly (intermediate certificates) or indirectly (through intermediate certificates). Therefore for a package containing and replacing the root certificates, trust is essential.
The same way, most users of Linux trust the CA root certificates provided by their distribution, it is very likely, that user would trust the CA root certificates provided by a package included in the Go standard library.
Additionally, the possibility to include the CA root certificates during build time, without altering the source code, is not possible with a 3rd party package but only if this package is included into the Go standard library and the build tag is implemented in to Go tool chain.
Update of the CA Root Certificates
The CA Root Certificates included in the standard library are updated with every release of Go (with the current schedule every 6 months). This would work the same way as it currently does for the package time/tzdata
. The update frequency of the Included CA Certificate List is roughly every few months (2020: 5 times, 2019: 4 times, according to curl ca extract), which seems to be similar to the update frequency of the time zone data information.
In regards to updating the CA root certificates compiled into a Go binary, the same limitations apply as for the time/tzdata
package. The information compiled into a binary is not updated. That being said, for the situations, this package is intended for, it is still an improvement because containers built FROM scratch
are also not updated by default and out of date / not updatable systems obviously also do not get updates for the CA root certificates.
Annex
There is a sample implementation of this approach at github.com/breml/rootcerts with some additional reasoning about when to use such a package and what to keep in mind.
This proposal as well as the sample implementation are highly influenced by the proposal #38017 - time/tzdata and the implementation of the package time/tzdata
by @ianlancetaylor
cc: @FiloSottile, @katiehockman, @mvdan