Repository: go
Issue: crypto/x509: CreateRevocationList over-enforces KeyUsage check
Labels: NeedsInvestigation

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.20.3 linux/amd64
</pre>

### Does this issue reproduce with the latest release?

Yes.

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/cipherboy/.cache/go-build"
GOENV="/home/cipherboy/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/cipherboy/go/pkg/mod"
GONOPROXY="github.com/hashicorp"
GONOSUMDB="github.com/hashicorp"
GOOS="linux"
GOPATH="/home/cipherboy/go"
GOPRIVATE="github.com/hashicorp"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.3"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/cipherboy/GitHub/cipherboy/vault/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build652088920=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

Attempt to use `x509.CreateRevocationList(...)` with an ITU X.509 compliant certificate lacking the `KeyUsage` extension.

### What did you expect to see?

CRL creation succeed.

### What did you see instead?

CRL creation failed due to this check:

https://github.com/golang/go/blob/0853f8caec60f59df234c287be7f5971ab62133f/src/crypto/x509/x509.go#L2299-L2301

### Additional Information

While [RFC 5280 is unclear about the behavior when the attribute is missing](https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3), it is clear that the extension MUST be added:

>    Conforming CAs MUST include this extension in certificates that
>    contain public keys that are used to validate digital signatures on
>    other public key certificates or CRLs.  When present, conforming CAs
>    SHOULD mark this extension as critical.

Per @maxb in [Vault#20137](https://github.com/hashicorp/vault/issues/20137#issuecomment-1511241701), this line about requiring the KeyUsage extension was added in [RFC 3280](https://datatracker.ietf.org/doc/html/rfc3280)'s rewrite of [RFC 2459](https://datatracker.ietf.org/doc/html/rfc2459).

However, the broader [ITU X.509](https://www.itu.int/rec/T-REC-X.509-201910-I/en) standard writes (on printed page 73/pdf page 83):

> keyUsage matches if all of the bits set in the presented value are also set in the key usage extension in the stored attribute value, or if there is no key usage extension in the stored attribute value.

meaning the behavior without this extension is quite clear (outside of PKIX space).

Additionally, it is unclear why Go would enforce this on CRL creation time: it seems more usefully to be a client-side check for CRL validity, than a CA generation enforcement mechanism. NSS [appears to handle](https://github.com/nss-dev/nss/blob/2fd7401aad7e5b311c817f7cc15f562a7ba38243/lib/certdb/certv3.c#L196-L222) this behavior correctly (thanks @stevendpclark for the reference), but we're having a hard time finding a reference for OpenSSL at the moment.

(There's probably an aside here about few people actually doing verification of CRLs -- most people presume they're transmitted over a pseudo-secure and/or simply fail to verify them altogether. And likely string together whatever pipeline they want to fetch it into their validating software (e.g., web server for mTLS cert auth)... But that's another discussion for another time...) :-) 

### Proposal

I'd propose eliding this check _if_ the issuer certificates lacks KU altogether, but otherwise persist it. This mirrors the behavior of ITU X.509, minimally violates RFC 5280, and aligns with NSS's behavior.

This would be aligned with [earlier precedence](https://github.com/golang/go/issues/11087).

See also: https://github.com/golang/go/issues/11087 
See also: https://github.com/golang/go/issues/49414