From 8ee0261865bea69f1a39e04a539e1152b7ba578d Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Sun, 30 Aug 2015 09:45:26 -0700 Subject: [PATCH] crypto/x509: make verification of an empty certificate consistent across platforms. Platform-specific verification needs the ASN.1 contents of a certificate but that might not be provided if the Certificate was not created by ParseCertificate. In order to avoid a panic on Windows, and to make behaviour consistent across platforms, this change causes verification to fail when the ASN.1 contents of a certificate are not available. Fixes #12184 Change-Id: I4395d74934e675c179eaf4cded1094a756e478bb Reviewed-on: https://go-review.googlesource.com/14053 Reviewed-by: Brad Fitzpatrick --- src/crypto/x509/verify.go | 18 ++++++++++++++++++ src/crypto/x509/x509_test.go | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go index 21b870c171..27e9bbfbcc 100644 --- a/src/crypto/x509/verify.go +++ b/src/crypto/x509/verify.go @@ -5,6 +5,7 @@ package x509 import ( + "errors" "fmt" "net" "runtime" @@ -122,6 +123,10 @@ func (SystemRootsError) Error() string { return "x509: failed to load system roots and no roots provided" } +// errNotParsed is returned when a certificate without ASN.1 contents is +// verified. Platform-specific verification needs the ASN.1 contents. +var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate") + // VerifyOptions contains parameters for Certificate.Verify. It's a structure // because other PKIX verification APIs have ended up needing many options. type VerifyOptions struct { @@ -210,6 +215,19 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V // // WARNING: this doesn't do any revocation checking. func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { + // Platform-specific verification needs the ASN.1 contents so + // this makes the behaviour consistent across platforms. + if len(c.Raw) == 0 { + return nil, errNotParsed + } + if opts.Intermediates != nil { + for _, intermediate := range opts.Intermediates.certs { + if len(intermediate.Raw) == 0 { + return nil, errNotParsed + } + } + } + // Use Windows's own verification and chain building. if opts.Roots == nil && runtime.GOOS == "windows" { return c.systemVerify(&opts) diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index fbd77dde8a..36dbc47931 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -1159,6 +1159,12 @@ func TestASN1BitLength(t *testing.T) { } } +func TestVerifyEmptyCertificate(t *testing.T) { + if _, err := new(Certificate).Verify(VerifyOptions{}); err != errNotParsed { + t.Errorf("Verifying empty certificate resulted in unexpected error: %q (wanted %q)", err, errNotParsed) + } +} + // These CSR was generated with OpenSSL: // openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf // -- 2.48.1