Description
The Go cryptographic libraries are currently split between the standard library and the golang.org/x/crypto module. This document discusses the issues with this split and proposes a plan to move the majority of the golang.org/x/crypto module into the standard library.
Current State
Currently, the Go cryptographic libraries are split across the standard library and the golang.org/x/crypto module. Why something is in x/crypto, versus the standard library, is often hard to explain (in many cases it is simply an artifact of how the golang.org/x tree was used historically), and seems consistently confusing to users (a persistent misconception is that the x/ tree is for “experimental” code), often dissuading them from relying on code in the module because of assumptions about quality or API stability.
The boundary between the standard library and x/crypto is further blurred as the standard library currently relies on a number of x/crypto packages (currently 7), which need to be vendored. This vendoring relationship additionally creates a complex security patching problem, requiring a special third process for how we patch these particular packages (separate from how we patch just the standard library, or just x/crypto).
The x/crypto module is, in theory, useful as a place to develop code that, while still abiding by the API backwards compatibility rules, is somewhat more experimental (despite x/ not meaning that) in that it may require a more fast paced development cycle than the standard library can reasonably provide (for example when developing implementations of new ciphers or protocols for which the specifications are still fluid).
In reality though, the x/crypto module is not generally used this way, and if we were to start doing this it would only encode the misconceptions people already have about the module. Building experimental or semi-unstable code in the module would also lead to the question of what to do with code once it stabilizes. If we decide to move stable code into the standard library we would end up with a series of wrapper packages in x/crypto which only serve to forward “completed” packages to their eventual standard library counterparts.
One exception to this is the x/crypto/ssh package, which has recently seen very rapid development. For many users, a lot of the newly introduced features and bug fixes are things they would like to start using immediately, and as such the release cadence of the standard library is likely too slow. Moving this package into the standard library could therefore create friction for these users. That said it isn’t clear that this is a strong enough reason not to migrate this package. We could split x/crypto/ssh into its own module, but it’s quite likely that the development cadence of this package will decrease significantly over time, at which point we’d likely want to revisit this decision and consider integrating it into the standard library. This seems like one more case in which it would be useful for the standard library to provide some mechanism for updating individual sections of the standard library out of step with the larger release cadence.
Proposal
The code in x/crypto has no discernable difference in quality or API stability than any code in the standard library (except for a small handful of notable exceptions, which will be addressed later). The vast majority of packages in x/crypto would be perfectly at home in the standard library crypto/ tree, and as such, they really should be in the standard library.
Moving the x/crypto packages into the standard library would communicate to users that we are confident in their quality and stability, and encourage their widespread adoption and usage, dispelling the commonly held misconceptions about the contents of x/crypto, and reducing the complexity that supporting this special additional module creates.
Migrating and Freezing x/crypto
The vast majority of packages in x/crypto should be moved, with little to no modification, into the crypto/ tree. This should be done during a single standard library release cycle (note: this should be done as close to the end of the release cycle as possible, to avoid having to keep the two copies of packages in sync. Ideally once we copy the packages into the standard library we should freeze both the x/crypto and standard library copy, and only unfreeze once the standard library tree re-opens, only accepting changes to the standard library version. The exact process for this is still up for debate).
Once the packages have been migrated to the standard library, the module should be split using build tags, leaving the current implementation as pre_go1{version} (i.e. +build !go1.24
) and adding wrappers which forward to the standard library version as post_go1{version} (i.e. +build go1.24
), and tagged as v1.0.0. This will allow users who don’t update to the newest version of Go to continue to use the x/crypto module, and allow us to backport security changes to x/crypto until at least two major versions into the future. We will not backport any non-security changes to x/crypto.
Two major versions after the transition (i.e., assuming we land this in 1.24, in 1.26), we will remove the build tagged prior implementation, leaving just the forwarders, tagging the (hopefully) final version of x/crypto.
Remaining Packages
There are a handful of packages which we do not want to move into the standard library, either because they require an update/release cadence that does not align with the standard library, or because they are frozen/deprecated, and this provides an opportunity to make a clean break.
In particular the release cadence for the x/crypto/x509roots package does not align with that of the standard library. This package needs to be updated on an arbitrary basis, and changes should be pulled in by users as quickly as possible, which is currently not possible for packages within the standard library. This package should be moved into its own standalone module, golang.org/x/x509roots (an argument could be made for leaving it in x/crypto but this goes against one of the main arguments for this move in the first place, which is that the x/crypto module is confusing, and leaving only one thing there which continues to be maintained is likely to only make that distinction even more confusing).
The following already deprecated/frozen packages will not be moved into the standard library, and the implementations will remain as-is in the v1 tagged golang.org/x/crypto module (#65250 proposes to deprecate/freeze a number of additional packages, if that proposal is accepted I will update this list to mirror that):
- twofish
- cast5
- tea
- xtea
- poly1305
- ripemd160
- bn256
- blowfish
- openpgp
- md4
- pkcs12
cc @FiloSottile @golang/security
Metadata
Metadata
Assignees
Type
Projects
Status