aboutsummaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2021-10-31 19:23:14 -0400
committerFilippo Valsorda <filippo@golang.org>2021-11-05 21:48:25 +0000
commit6b223e872a255b2722ea921c9d42adcbb5d1d4d5 (patch)
tree0995ad18cce563456310811cd1856446042537a7 /src/crypto
parentbb53fd740c599dd72c2abdab045ca34a9395ea13 (diff)
downloadgo-6b223e872a255b2722ea921c9d42adcbb5d1d4d5.tar.gz
go-6b223e872a255b2722ea921c9d42adcbb5d1d4d5.zip
crypto/x509: disable SHA-1 signature verification
Updates #41682 Change-Id: Ib766d2587d54dd3aeff8ecab389741df5e8af7cc Reviewed-on: https://go-review.googlesource.com/c/go/+/359777 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Filippo Valsorda <filippo@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
Diffstat (limited to 'src/crypto')
-rw-r--r--src/crypto/x509/verify_test.go4
-rw-r--r--src/crypto/x509/x509.go39
-rw-r--r--src/crypto/x509/x509_test.go75
3 files changed, 90 insertions, 28 deletions
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index df78abd77e..b9b71f4c1e 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -534,6 +534,10 @@ func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
}
func TestGoVerify(t *testing.T) {
+ // Temporarily enable SHA-1 verification since a number of test chains
+ // require it. TODO(filippo): regenerate test chains.
+ defer func(old bool) { debugAllowSHA1 = old }(debugAllowSHA1)
+ debugAllowSHA1 = true
for _, test := range verifyTests {
t.Run(test.name, func(t *testing.T) {
testVerify(t, test, false)
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 4304ab54e1..b5c2b22cd7 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -18,6 +18,7 @@ import (
"encoding/pem"
"errors"
"fmt"
+ "internal/godebug"
"io"
"math/big"
"net"
@@ -181,15 +182,15 @@ type SignatureAlgorithm int
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
- MD2WithRSA // Unsupported.
- MD5WithRSA // Only supported for signing, not verification.
- SHA1WithRSA
+ MD2WithRSA // Unsupported.
+ MD5WithRSA // Only supported for signing, not verification.
+ SHA1WithRSA // Only supported for signing, not verification.
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
DSAWithSHA1 // Unsupported.
DSAWithSHA256 // Unsupported.
- ECDSAWithSHA1
+ ECDSAWithSHA1 // Only supported for signing, not verification.
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
@@ -729,11 +730,23 @@ type Certificate struct {
// involves algorithms that are not currently implemented.
var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
-// An InsecureAlgorithmError
+// debugAllowSHA1 allows SHA-1 signatures. See issue 41682.
+var debugAllowSHA1 = godebug.Get("x509sha1") == "1"
+
+// An InsecureAlgorithmError indicates that the SignatureAlgorithm used to
+// generate the signature is not secure, and the signature has been rejected.
+//
+// To temporarily restore support for SHA-1 signatures, include the value
+// "x509sha1=1" in the GODEBUG environment variable. Note that this option will
+// be removed in Go 1.19.
type InsecureAlgorithmError SignatureAlgorithm
func (e InsecureAlgorithmError) Error() string {
- return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e))
+ var override string
+ if SignatureAlgorithm(e) == SHA1WithRSA || SignatureAlgorithm(e) == ECDSAWithSHA1 {
+ override = " (temporarily override with GODEBUG=x509sha1=1)"
+ }
+ return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e)) + override
}
// ConstraintViolationError results when a requested usage is not permitted by
@@ -825,6 +838,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
}
case crypto.MD5:
return InsecureAlgorithmError(algo)
+ case crypto.SHA1:
+ if !debugAllowSHA1 {
+ return InsecureAlgorithmError(algo)
+ }
+ fallthrough
default:
if !hashType.Available() {
return ErrUnsupportedAlgorithm
@@ -1579,9 +1597,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
}
// Check the signature to ensure the crypto.Signer behaved correctly.
- // We skip this check if the signature algorithm is MD5WithRSA as we
- // only support this algorithm for signing, and not verification.
- if sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm); sigAlg != MD5WithRSA {
+ sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm)
+ switch sigAlg {
+ case MD5WithRSA, SHA1WithRSA, ECDSAWithSHA1:
+ // We skip the check if the signature algorithm is only supported for
+ // signing, not verification.
+ default:
if err := checkSignature(sigAlg, c.Raw, signature, key.Public()); err != nil {
return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index a4053abf41..affab3789d 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -585,10 +585,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
checkSig bool
sigAlgo SignatureAlgorithm
}{
- {"RSA/RSA", &testPrivateKey.PublicKey, testPrivateKey, true, SHA1WithRSA},
+ {"RSA/RSA", &testPrivateKey.PublicKey, testPrivateKey, true, SHA384WithRSA},
{"RSA/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
{"ECDSA/RSA", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSA},
- {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
+ {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA256},
{"RSAPSS/RSAPSS", &testPrivateKey.PublicKey, testPrivateKey, true, SHA256WithRSAPSS},
{"ECDSA/RSAPSS", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSAPSS},
{"RSAPSS/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
@@ -886,7 +886,6 @@ var ecdsaTests = []struct {
sigAlgo SignatureAlgorithm
pemCert string
}{
- {ECDSAWithSHA1, ecdsaSHA1CertPem},
{ECDSAWithSHA256, ecdsaSHA256p256CertPem},
{ECDSAWithSHA256, ecdsaSHA256p384CertPem},
{ECDSAWithSHA384, ecdsaSHA384p521CertPem},
@@ -1389,10 +1388,10 @@ func TestCreateCertificateRequest(t *testing.T) {
priv interface{}
sigAlgo SignatureAlgorithm
}{
- {"RSA", testPrivateKey, SHA1WithRSA},
- {"ECDSA-256", ecdsa256Priv, ECDSAWithSHA1},
- {"ECDSA-384", ecdsa384Priv, ECDSAWithSHA1},
- {"ECDSA-521", ecdsa521Priv, ECDSAWithSHA1},
+ {"RSA", testPrivateKey, SHA256WithRSA},
+ {"ECDSA-256", ecdsa256Priv, ECDSAWithSHA256},
+ {"ECDSA-384", ecdsa384Priv, ECDSAWithSHA256},
+ {"ECDSA-521", ecdsa521Priv, ECDSAWithSHA256},
{"Ed25519", ed25519Priv, PureEd25519},
}
@@ -1783,6 +1782,9 @@ func TestInsecureAlgorithmErrorString(t *testing.T) {
sa SignatureAlgorithm
want string
}{
+ {MD5WithRSA, "x509: cannot verify signature: insecure algorithm MD5-RSA"},
+ {SHA1WithRSA, "x509: cannot verify signature: insecure algorithm SHA1-RSA (temporarily override with GODEBUG=x509sha1=1)"},
+ {ECDSAWithSHA1, "x509: cannot verify signature: insecure algorithm ECDSA-SHA1 (temporarily override with GODEBUG=x509sha1=1)"},
{MD2WithRSA, "x509: cannot verify signature: insecure algorithm MD2-RSA"},
{-1, "x509: cannot verify signature: insecure algorithm -1"},
{0, "x509: cannot verify signature: insecure algorithm 0"},
@@ -1846,6 +1848,30 @@ func TestMD5(t *testing.T) {
}
}
+func TestSHA1(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(ecdsaSHA1CertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+ if sa := cert.SignatureAlgorithm; sa != ECDSAWithSHA1 {
+ t.Errorf("signature algorithm is %v, want %v", sa, ECDSAWithSHA1)
+ }
+ if err = cert.CheckSignatureFrom(cert); err == nil {
+ t.Fatalf("certificate verification succeeded incorrectly")
+ }
+ if _, ok := err.(InsecureAlgorithmError); !ok {
+ t.Fatalf("certificate verification returned %v (%T), wanted InsecureAlgorithmError", err, err)
+ }
+
+ defer func(old bool) { debugAllowSHA1 = old }(debugAllowSHA1)
+ debugAllowSHA1 = true
+
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatalf("SHA-1 certificate did not verify with GODEBUG=x509sha1=1: %v", err)
+ }
+}
+
// certMissingRSANULL contains an RSA public key where the AlgorithmIdentifier
// parameters are omitted rather than being an ASN.1 NULL.
const certMissingRSANULL = `
@@ -2897,19 +2923,31 @@ func TestCreateCertificateBrokenSigner(t *testing.T) {
}
}
-func TestCreateCertificateMD5(t *testing.T) {
- template := &Certificate{
- SerialNumber: big.NewInt(10),
- DNSNames: []string{"example.com"},
- SignatureAlgorithm: MD5WithRSA,
- }
- k, err := rsa.GenerateKey(rand.Reader, 1024)
+func TestCreateCertificateLegacy(t *testing.T) {
+ ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
- t.Fatalf("failed to generate test key: %s", err)
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
}
- _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
- if err != nil {
- t.Fatalf("CreateCertificate failed when SignatureAlgorithm = MD5WithRSA: %s", err)
+
+ for _, sigAlg := range []SignatureAlgorithm{
+ MD5WithRSA, SHA1WithRSA, ECDSAWithSHA1,
+ } {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ SignatureAlgorithm: sigAlg,
+ }
+ var k crypto.Signer
+ switch sigAlg {
+ case MD5WithRSA, SHA1WithRSA:
+ k = testPrivateKey
+ case ECDSAWithSHA1:
+ k = ecdsaPriv
+ }
+ _, err := CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+ if err != nil {
+ t.Fatalf("CreateCertificate failed when SignatureAlgorithm = %v: %s", sigAlg, err)
+ }
}
}
@@ -3131,7 +3169,6 @@ func TestParseCertificateRawEquals(t *testing.T) {
if !bytes.Equal(p.Bytes, cert.Raw) {
t.Fatalf("unexpected Certificate.Raw\ngot: %x\nwant: %x\n", cert.Raw, p.Bytes)
}
- fmt.Printf("in: %x\nout: %x\n", p.Bytes, cert.Raw)
}
// mismatchingSigAlgIDPEM contains a certificate where the Certificate