Skip to content

Commit 35998c0

Browse files
rolandshoemakergopherbot
authored andcommitted
crypto/x509: only disable SHA-1 verification for certificates
Disable SHA-1 signature verification in Certificate.CheckSignatureFrom, but not in Certificate.CheckSignature. This allows verification of OCSP responses and CRLs, which still use SHA-1 signatures, but not on certificates. Updates #41682 Change-Id: Ia705eb5052e6fc2724fed59248b1c4ef8af6c3fe Reviewed-on: https://go-review.googlesource.com/c/go/+/394294 Trust: Roland Shoemaker <[email protected]> Run-TryBot: Roland Shoemaker <[email protected]> Auto-Submit: Roland Shoemaker <[email protected]> Reviewed-by: Jordan Liggitt <[email protected]> Reviewed-by: Filippo Valsorda <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent efbe17d commit 35998c0

File tree

3 files changed

+85
-34
lines changed

3 files changed

+85
-34
lines changed

src/crypto/x509/verify.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
724724
// list. (While this is not specified, it is common practice in order to limit
725725
// the types of certificates a CA can issue.)
726726
//
727+
// Certificates that use SHA1WithRSA and ECDSAWithSHA1 signatures are not supported,
728+
// and will not be used to build chains.
729+
//
727730
// WARNING: this function doesn't do any revocation checking.
728731
func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
729732
// Platform-specific verification needs the ASN.1 contents so

src/crypto/x509/x509.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -184,13 +184,13 @@ const (
184184

185185
MD2WithRSA // Unsupported.
186186
MD5WithRSA // Only supported for signing, not verification.
187-
SHA1WithRSA // Only supported for signing, not verification.
187+
SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
188188
SHA256WithRSA
189189
SHA384WithRSA
190190
SHA512WithRSA
191191
DSAWithSHA1 // Unsupported.
192192
DSAWithSHA256 // Unsupported.
193-
ECDSAWithSHA1 // Only supported for signing, not verification.
193+
ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
194194
ECDSAWithSHA256
195195
ECDSAWithSHA384
196196
ECDSAWithSHA512
@@ -767,7 +767,7 @@ func (c *Certificate) hasSANExtension() bool {
767767
}
768768

769769
// CheckSignatureFrom verifies that the signature on c is a valid signature
770-
// from parent.
770+
// from parent. SHA1WithRSA and ECDSAWithSHA1 signatures are not supported.
771771
func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
772772
// RFC 5280, 4.2.1.9:
773773
// "If the basic constraints extension is not present in a version 3
@@ -789,13 +789,13 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
789789

790790
// TODO(agl): don't ignore the path length constraint.
791791

792-
return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
792+
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, debugAllowSHA1)
793793
}
794794

795795
// CheckSignature verifies that signature is a valid signature over signed from
796796
// c's public key.
797797
func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
798-
return checkSignature(algo, signed, signature, c.PublicKey)
798+
return checkSignature(algo, signed, signature, c.PublicKey, true)
799799
}
800800

801801
func (c *Certificate) hasNameConstraints() bool {
@@ -815,9 +815,9 @@ func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm,
815815
return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey)
816816
}
817817

818-
// CheckSignature verifies that signature is a valid signature over signed from
818+
// checkSignature verifies that signature is a valid signature over signed from
819819
// a crypto.PublicKey.
820-
func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
820+
func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey, allowSHA1 bool) (err error) {
821821
var hashType crypto.Hash
822822
var pubKeyAlgo PublicKeyAlgorithm
823823

@@ -836,7 +836,7 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
836836
case crypto.MD5:
837837
return InsecureAlgorithmError(algo)
838838
case crypto.SHA1:
839-
if !debugAllowSHA1 {
839+
if !allowSHA1 {
840840
return InsecureAlgorithmError(algo)
841841
}
842842
fallthrough
@@ -1584,11 +1584,11 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
15841584
// Check the signature to ensure the crypto.Signer behaved correctly.
15851585
sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm)
15861586
switch sigAlg {
1587-
case MD5WithRSA, SHA1WithRSA, ECDSAWithSHA1:
1587+
case MD5WithRSA:
15881588
// We skip the check if the signature algorithm is only supported for
15891589
// signing, not verification.
15901590
default:
1591-
if err := checkSignature(sigAlg, c.Raw, signature, key.Public()); err != nil {
1591+
if err := checkSignature(sigAlg, c.Raw, signature, key.Public(), true); err != nil {
15921592
return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
15931593
}
15941594
}
@@ -2067,7 +2067,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
20672067

20682068
// CheckSignature reports whether the signature on c is valid.
20692069
func (c *CertificateRequest) CheckSignature() error {
2070-
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
2070+
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true)
20712071
}
20722072

20732073
// RevocationList contains the fields used to create an X.509 v2 Certificate

src/crypto/x509/x509_test.go

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,30 +2924,15 @@ func TestCreateCertificateBrokenSigner(t *testing.T) {
29242924
}
29252925

29262926
func TestCreateCertificateLegacy(t *testing.T) {
2927-
ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
2928-
if err != nil {
2929-
t.Fatalf("Failed to generate ECDSA key: %s", err)
2927+
sigAlg := MD5WithRSA
2928+
template := &Certificate{
2929+
SerialNumber: big.NewInt(10),
2930+
DNSNames: []string{"example.com"},
2931+
SignatureAlgorithm: sigAlg,
29302932
}
2931-
2932-
for _, sigAlg := range []SignatureAlgorithm{
2933-
MD5WithRSA, SHA1WithRSA, ECDSAWithSHA1,
2934-
} {
2935-
template := &Certificate{
2936-
SerialNumber: big.NewInt(10),
2937-
DNSNames: []string{"example.com"},
2938-
SignatureAlgorithm: sigAlg,
2939-
}
2940-
var k crypto.Signer
2941-
switch sigAlg {
2942-
case MD5WithRSA, SHA1WithRSA:
2943-
k = testPrivateKey
2944-
case ECDSAWithSHA1:
2945-
k = ecdsaPriv
2946-
}
2947-
_, err := CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
2948-
if err != nil {
2949-
t.Fatalf("CreateCertificate failed when SignatureAlgorithm = %v: %s", sigAlg, err)
2950-
}
2933+
_, err := CreateCertificate(rand.Reader, template, template, testPrivateKey.Public(), &brokenSigner{testPrivateKey.Public()})
2934+
if err != nil {
2935+
t.Fatalf("CreateCertificate failed when SignatureAlgorithm = %v: %s", sigAlg, err)
29512936
}
29522937
}
29532938

@@ -3396,3 +3381,66 @@ func TestParseUniqueID(t *testing.T) {
33963381
t.Fatalf("unexpected number of extensions (probably because the extension section was not parsed): got %d, want 7", len(cert.Extensions))
33973382
}
33983383
}
3384+
3385+
func TestDisableSHA1ForCertOnly(t *testing.T) {
3386+
defer func(old bool) { debugAllowSHA1 = old }(debugAllowSHA1)
3387+
debugAllowSHA1 = false
3388+
3389+
tmpl := &Certificate{
3390+
SerialNumber: big.NewInt(1),
3391+
NotBefore: time.Now().Add(-time.Hour),
3392+
NotAfter: time.Now().Add(time.Hour),
3393+
SignatureAlgorithm: SHA1WithRSA,
3394+
BasicConstraintsValid: true,
3395+
IsCA: true,
3396+
KeyUsage: KeyUsageCertSign | KeyUsageCRLSign,
3397+
}
3398+
certDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, rsaPrivateKey.Public(), rsaPrivateKey)
3399+
if err != nil {
3400+
t.Fatalf("failed to generate test cert: %s", err)
3401+
}
3402+
cert, err := ParseCertificate(certDER)
3403+
if err != nil {
3404+
t.Fatalf("failed to parse test cert: %s", err)
3405+
}
3406+
3407+
err = cert.CheckSignatureFrom(cert)
3408+
if err == nil {
3409+
t.Error("expected CheckSignatureFrom to fail")
3410+
} else if _, ok := err.(InsecureAlgorithmError); !ok {
3411+
t.Errorf("expected InsecureAlgorithmError error, got %T", err)
3412+
}
3413+
3414+
crlDER, err := CreateRevocationList(rand.Reader, &RevocationList{
3415+
SignatureAlgorithm: SHA1WithRSA,
3416+
Number: big.NewInt(1),
3417+
ThisUpdate: time.Now().Add(-time.Hour),
3418+
NextUpdate: time.Now().Add(time.Hour),
3419+
}, cert, rsaPrivateKey)
3420+
if err != nil {
3421+
t.Fatalf("failed to generate test CRL: %s", err)
3422+
}
3423+
// TODO(rolandshoemaker): this should be ParseRevocationList once it lands
3424+
crl, err := ParseCRL(crlDER)
3425+
if err != nil {
3426+
t.Fatalf("failed to parse test CRL: %s", err)
3427+
}
3428+
3429+
if err = cert.CheckCRLSignature(crl); err != nil {
3430+
t.Errorf("unexpected error: %s", err)
3431+
}
3432+
3433+
// This is an unrelated OCSP response, which will fail signature verification
3434+
// but shouldn't return a InsecureAlgorithmError, since SHA1 should be allowed
3435+
// for OCSP.
3436+
ocspTBSHex := "30819fa2160414884451ff502a695e2d88f421bad90cf2cecbea7c180f32303133303631383037323434335a30743072304a300906052b0e03021a0500041448b60d38238df8456e4ee5843ea394111802979f0414884451ff502a695e2d88f421bad90cf2cecbea7c021100f78b13b946fc9635d8ab49de9d2148218000180f32303133303631383037323434335aa011180f32303133303632323037323434335a"
3437+
ocspTBS, err := hex.DecodeString(ocspTBSHex)
3438+
if err != nil {
3439+
t.Fatalf("failed to decode OCSP response TBS hex: %s", err)
3440+
}
3441+
3442+
err = cert.CheckSignature(SHA1WithRSA, ocspTBS, nil)
3443+
if err != rsa.ErrVerification {
3444+
t.Errorf("unexpected error: %s", err)
3445+
}
3446+
}

0 commit comments

Comments
 (0)