mirror of https://github.com/golang/go.git
crypto/x509: cleanup signature generation
Centralizing some repetitive code, which would have prevented #45990. This also fixes the deprecated Certificate.CreateCRL for RSA-PSS, not that anyone cared, probably. This has two other minor observable behavior changes: MD2 is now treated as a completely unknown algorithm (why did we even have that!? removing lets us treat hash == 0 as always meaning no prehash); and we now do the signature verification self-check for all signing operations. Change-Id: I3b34fe0c3b6eb6181d2145b0704834225cd45a27 Reviewed-on: https://go-review.googlesource.com/c/go/+/586015 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
bf0bbd5360
commit
c96159c252
|
|
@ -0,0 +1,3 @@
|
||||||
|
[CreateCertificateRequest] now correct supports RSA-PSS signature algorithms.
|
||||||
|
|
||||||
|
[CreateCertificateRequest] and [CreateRevocationList] now verify the generated signature using the signer’s public key. If the signature is invalid, an error is returned. This has been the behavior of [CreateCertificate] since Go 1.16.
|
||||||
|
|
@ -233,12 +233,21 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (algo SignatureAlgorithm) isRSAPSS() bool {
|
func (algo SignatureAlgorithm) isRSAPSS() bool {
|
||||||
switch algo {
|
for _, details := range signatureAlgorithmDetails {
|
||||||
case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
|
if details.algo == algo {
|
||||||
return true
|
return details.isRSAPSS
|
||||||
default:
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (algo SignatureAlgorithm) hashFunc() crypto.Hash {
|
||||||
|
for _, details := range signatureAlgorithmDetails {
|
||||||
|
if details.algo == algo {
|
||||||
|
return details.hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crypto.Hash(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (algo SignatureAlgorithm) String() string {
|
func (algo SignatureAlgorithm) String() string {
|
||||||
|
|
@ -281,8 +290,6 @@ func (algo PublicKeyAlgorithm) String() string {
|
||||||
//
|
//
|
||||||
// RFC 3279 2.2.1 RSA Signature Algorithms
|
// RFC 3279 2.2.1 RSA Signature Algorithms
|
||||||
//
|
//
|
||||||
// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
|
|
||||||
//
|
|
||||||
// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
|
// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
|
||||||
//
|
//
|
||||||
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
|
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
|
||||||
|
|
@ -325,7 +332,6 @@ func (algo PublicKeyAlgorithm) String() string {
|
||||||
//
|
//
|
||||||
// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
|
// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
|
||||||
var (
|
var (
|
||||||
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
|
|
||||||
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
|
||||||
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
|
||||||
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
|
||||||
|
|
@ -356,40 +362,43 @@ var signatureAlgorithmDetails = []struct {
|
||||||
algo SignatureAlgorithm
|
algo SignatureAlgorithm
|
||||||
name string
|
name string
|
||||||
oid asn1.ObjectIdentifier
|
oid asn1.ObjectIdentifier
|
||||||
|
params asn1.RawValue
|
||||||
pubKeyAlgo PublicKeyAlgorithm
|
pubKeyAlgo PublicKeyAlgorithm
|
||||||
hash crypto.Hash
|
hash crypto.Hash
|
||||||
|
isRSAPSS bool
|
||||||
}{
|
}{
|
||||||
{MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
|
{MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false},
|
||||||
{MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5},
|
{SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
|
||||||
{SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
|
{SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
|
||||||
{SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
|
{SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false},
|
||||||
{SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
|
{SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false},
|
||||||
{SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
|
{SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false},
|
||||||
{SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
|
{SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true},
|
||||||
{SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256},
|
{SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true},
|
||||||
{SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384},
|
{SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true},
|
||||||
{SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512},
|
{DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false},
|
||||||
{DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
|
{DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false},
|
||||||
{DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
|
{ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false},
|
||||||
{ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
|
{ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false},
|
||||||
{ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
|
{ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false},
|
||||||
{ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
|
{ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false},
|
||||||
{ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
|
{PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false},
|
||||||
{PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hashToPSSParameters contains the DER encoded RSA PSS parameters for the
|
var emptyRawValue = asn1.RawValue{}
|
||||||
|
|
||||||
|
// DER encoded RSA PSS parameters for the
|
||||||
// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
|
// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
|
||||||
// The parameters contain the following values:
|
// The parameters contain the following values:
|
||||||
// - hashAlgorithm contains the associated hash identifier with NULL parameters
|
// - hashAlgorithm contains the associated hash identifier with NULL parameters
|
||||||
// - maskGenAlgorithm always contains the default mgf1SHA1 identifier
|
// - maskGenAlgorithm always contains the default mgf1SHA1 identifier
|
||||||
// - saltLength contains the length of the associated hash
|
// - saltLength contains the length of the associated hash
|
||||||
// - trailerField always contains the default trailerFieldBC value
|
// - trailerField always contains the default trailerFieldBC value
|
||||||
var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
|
var (
|
||||||
crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}},
|
pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}}
|
||||||
crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}},
|
pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}}
|
||||||
crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}},
|
pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}}
|
||||||
}
|
)
|
||||||
|
|
||||||
// pssParameters reflects the parameters in an AlgorithmIdentifier that
|
// pssParameters reflects the parameters in an AlgorithmIdentifier that
|
||||||
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
|
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
|
||||||
|
|
@ -1436,81 +1445,91 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
|
||||||
return asn1.Marshal(cert.Subject.ToRDNSequence())
|
return asn1.Marshal(cert.Subject.ToRDNSequence())
|
||||||
}
|
}
|
||||||
|
|
||||||
// signingParamsForPublicKey returns the parameters to use for signing with
|
// signingParamsForKey returns the signature algorithm and its Algorithm
|
||||||
// priv. If requestedSigAlgo is not zero then it overrides the default
|
// Identifier to use for signing, based on the key type. If sigAlgo is not zero
|
||||||
// signature algorithm.
|
// then it overrides the default.
|
||||||
func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
|
func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) {
|
||||||
|
var ai pkix.AlgorithmIdentifier
|
||||||
var pubType PublicKeyAlgorithm
|
var pubType PublicKeyAlgorithm
|
||||||
|
var defaultAlgo SignatureAlgorithm
|
||||||
|
|
||||||
switch pub := pub.(type) {
|
switch pub := key.Public().(type) {
|
||||||
case *rsa.PublicKey:
|
case *rsa.PublicKey:
|
||||||
pubType = RSA
|
pubType = RSA
|
||||||
hashFunc = crypto.SHA256
|
defaultAlgo = SHA256WithRSA
|
||||||
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
|
|
||||||
sigAlgo.Parameters = asn1.NullRawValue
|
|
||||||
|
|
||||||
case *ecdsa.PublicKey:
|
case *ecdsa.PublicKey:
|
||||||
pubType = ECDSA
|
pubType = ECDSA
|
||||||
|
|
||||||
switch pub.Curve {
|
switch pub.Curve {
|
||||||
case elliptic.P224(), elliptic.P256():
|
case elliptic.P224(), elliptic.P256():
|
||||||
hashFunc = crypto.SHA256
|
defaultAlgo = ECDSAWithSHA256
|
||||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
|
|
||||||
case elliptic.P384():
|
case elliptic.P384():
|
||||||
hashFunc = crypto.SHA384
|
defaultAlgo = ECDSAWithSHA384
|
||||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
|
|
||||||
case elliptic.P521():
|
case elliptic.P521():
|
||||||
hashFunc = crypto.SHA512
|
defaultAlgo = ECDSAWithSHA512
|
||||||
sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
|
|
||||||
default:
|
default:
|
||||||
err = errors.New("x509: unknown elliptic curve")
|
return 0, ai, errors.New("x509: unsupported elliptic curve")
|
||||||
}
|
}
|
||||||
|
|
||||||
case ed25519.PublicKey:
|
case ed25519.PublicKey:
|
||||||
pubType = Ed25519
|
pubType = Ed25519
|
||||||
sigAlgo.Algorithm = oidSignatureEd25519
|
defaultAlgo = PureEd25519
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
|
return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if sigAlgo == 0 {
|
||||||
return
|
sigAlgo = defaultAlgo
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestedSigAlgo == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, details := range signatureAlgorithmDetails {
|
for _, details := range signatureAlgorithmDetails {
|
||||||
if details.algo == requestedSigAlgo {
|
if details.algo == sigAlgo {
|
||||||
if details.pubKeyAlgo != pubType {
|
if details.pubKeyAlgo != pubType {
|
||||||
err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
|
return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
sigAlgo.Algorithm, hashFunc = details.oid, details.hash
|
if details.hash == crypto.MD5 {
|
||||||
if hashFunc == 0 && pubType != Ed25519 {
|
return 0, ai, errors.New("x509: signing with MD5 is not supported")
|
||||||
err = errors.New("x509: cannot sign with hash function requested")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if hashFunc == crypto.MD5 {
|
|
||||||
err = errors.New("x509: signing with MD5 is not supported")
|
return sigAlgo, pkix.AlgorithmIdentifier{
|
||||||
return
|
Algorithm: details.oid,
|
||||||
}
|
Parameters: details.params,
|
||||||
if requestedSigAlgo.isRSAPSS() {
|
}, nil
|
||||||
sigAlgo.Parameters = hashToPSSParameters[hashFunc]
|
|
||||||
}
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
return 0, ai, errors.New("x509: unknown SignatureAlgorithm")
|
||||||
err = errors.New("x509: unknown SignatureAlgorithm")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.Reader) ([]byte, error) {
|
||||||
|
signed := tbs
|
||||||
|
hashFunc := sigAlg.hashFunc()
|
||||||
|
if hashFunc != 0 {
|
||||||
|
h := hashFunc.New()
|
||||||
|
h.Write(signed)
|
||||||
|
signed = h.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var signerOpts crypto.SignerOpts = hashFunc
|
||||||
|
if sigAlg.isRSAPSS() {
|
||||||
|
signerOpts = &rsa.PSSOptions{
|
||||||
|
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
||||||
|
Hash: hashFunc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signature, err := key.Sign(rand, signed, signerOpts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the signature to ensure the crypto.Signer behaved correctly.
|
||||||
|
if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil {
|
||||||
|
return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return signature, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is
|
// emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is
|
||||||
|
|
@ -1600,7 +1619,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
||||||
return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
|
return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
|
||||||
}
|
}
|
||||||
|
|
||||||
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
|
signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1657,7 +1676,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
||||||
c := tbsCertificate{
|
c := tbsCertificate{
|
||||||
Version: 2,
|
Version: 2,
|
||||||
SerialNumber: template.SerialNumber,
|
SerialNumber: template.SerialNumber,
|
||||||
SignatureAlgorithm: signatureAlgorithm,
|
SignatureAlgorithm: algorithmIdentifier,
|
||||||
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
|
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
|
||||||
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
|
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
|
||||||
Subject: asn1.RawValue{FullBytes: asn1Subject},
|
Subject: asn1.RawValue{FullBytes: asn1Subject},
|
||||||
|
|
@ -1671,42 +1690,16 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
|
||||||
}
|
}
|
||||||
c.Raw = tbsCertContents
|
c.Raw = tbsCertContents
|
||||||
|
|
||||||
signed := tbsCertContents
|
signature, err := signTBS(tbsCertContents, key, signatureAlgorithm, rand)
|
||||||
if hashFunc != 0 {
|
|
||||||
h := hashFunc.New()
|
|
||||||
h.Write(signed)
|
|
||||||
signed = h.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var signerOpts crypto.SignerOpts = hashFunc
|
|
||||||
if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
|
|
||||||
signerOpts = &rsa.PSSOptions{
|
|
||||||
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
|
||||||
Hash: hashFunc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var signature []byte
|
|
||||||
signature, err = key.Sign(rand, signed, signerOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
signedCert, err := asn1.Marshal(certificate{
|
return asn1.Marshal(certificate{
|
||||||
c,
|
TBSCertificate: c,
|
||||||
signatureAlgorithm,
|
SignatureAlgorithm: algorithmIdentifier,
|
||||||
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the signature to ensure the crypto.Signer behaved correctly.
|
|
||||||
if err := checkSignature(getSignatureAlgorithmFromAI(signatureAlgorithm), c.Raw, signature, key.Public(), true); err != nil {
|
|
||||||
return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return signedCert, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
|
// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
|
||||||
|
|
@ -1756,7 +1749,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re
|
||||||
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
|
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
|
||||||
}
|
}
|
||||||
|
|
||||||
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
|
signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1770,7 +1763,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re
|
||||||
|
|
||||||
tbsCertList := pkix.TBSCertificateList{
|
tbsCertList := pkix.TBSCertificateList{
|
||||||
Version: 1,
|
Version: 1,
|
||||||
Signature: signatureAlgorithm,
|
Signature: algorithmIdentifier,
|
||||||
Issuer: c.Subject.ToRDNSequence(),
|
Issuer: c.Subject.ToRDNSequence(),
|
||||||
ThisUpdate: now.UTC(),
|
ThisUpdate: now.UTC(),
|
||||||
NextUpdate: expiry.UTC(),
|
NextUpdate: expiry.UTC(),
|
||||||
|
|
@ -1783,32 +1776,25 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re
|
||||||
aki.Id = oidExtensionAuthorityKeyId
|
aki.Id = oidExtensionAuthorityKeyId
|
||||||
aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
|
aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
|
tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
|
||||||
}
|
}
|
||||||
|
|
||||||
tbsCertListContents, err := asn1.Marshal(tbsCertList)
|
tbsCertListContents, err := asn1.Marshal(tbsCertList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
tbsCertList.Raw = tbsCertListContents
|
||||||
|
|
||||||
signed := tbsCertListContents
|
signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand)
|
||||||
if hashFunc != 0 {
|
|
||||||
h := hashFunc.New()
|
|
||||||
h.Write(signed)
|
|
||||||
signed = h.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var signature []byte
|
|
||||||
signature, err = key.Sign(rand, signed, hashFunc)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return asn1.Marshal(pkix.CertificateList{
|
return asn1.Marshal(pkix.CertificateList{
|
||||||
TBSCertList: tbsCertList,
|
TBSCertList: tbsCertList,
|
||||||
SignatureAlgorithm: signatureAlgorithm,
|
SignatureAlgorithm: algorithmIdentifier,
|
||||||
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -1976,9 +1962,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
|
||||||
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
|
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
|
||||||
}
|
}
|
||||||
|
|
||||||
var hashFunc crypto.Hash
|
signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm)
|
||||||
var sigAlgo pkix.AlgorithmIdentifier
|
|
||||||
hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -2050,7 +2034,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
|
||||||
|
|
||||||
rawAttributes, err := newRawAttributes(attributes)
|
rawAttributes, err := newRawAttributes(attributes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not included in attributes, add a new attribute for the
|
// If not included in attributes, add a new attribute for the
|
||||||
|
|
@ -2100,38 +2084,19 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
|
||||||
|
|
||||||
tbsCSRContents, err := asn1.Marshal(tbsCSR)
|
tbsCSRContents, err := asn1.Marshal(tbsCSR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
tbsCSR.Raw = tbsCSRContents
|
tbsCSR.Raw = tbsCSRContents
|
||||||
|
|
||||||
signed := tbsCSRContents
|
signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand)
|
||||||
if hashFunc != 0 {
|
|
||||||
h := hashFunc.New()
|
|
||||||
h.Write(signed)
|
|
||||||
signed = h.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
var signerOpts crypto.SignerOpts = hashFunc
|
|
||||||
if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
|
|
||||||
signerOpts = &rsa.PSSOptions{
|
|
||||||
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
|
||||||
Hash: hashFunc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var signature []byte
|
|
||||||
signature, err = key.Sign(rand, signed, signerOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return asn1.Marshal(certificateRequest{
|
return asn1.Marshal(certificateRequest{
|
||||||
TBSCSR: tbsCSR,
|
TBSCSR: tbsCSR,
|
||||||
SignatureAlgorithm: sigAlgo,
|
SignatureAlgorithm: algorithmIdentifier,
|
||||||
SignatureValue: asn1.BitString{
|
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
||||||
Bytes: signature,
|
|
||||||
BitLength: len(signature) * 8,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2359,7 +2324,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert
|
||||||
return nil, errors.New("x509: template contains nil Number field")
|
return nil, errors.New("x509: template contains nil Number field")
|
||||||
}
|
}
|
||||||
|
|
||||||
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
|
signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(priv, template.SignatureAlgorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -2443,7 +2408,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert
|
||||||
|
|
||||||
tbsCertList := tbsCertificateList{
|
tbsCertList := tbsCertificateList{
|
||||||
Version: 1, // v2
|
Version: 1, // v2
|
||||||
Signature: signatureAlgorithm,
|
Signature: algorithmIdentifier,
|
||||||
Issuer: asn1.RawValue{FullBytes: issuerSubject},
|
Issuer: asn1.RawValue{FullBytes: issuerSubject},
|
||||||
ThisUpdate: template.ThisUpdate.UTC(),
|
ThisUpdate: template.ThisUpdate.UTC(),
|
||||||
NextUpdate: template.NextUpdate.UTC(),
|
NextUpdate: template.NextUpdate.UTC(),
|
||||||
|
|
@ -2475,28 +2440,14 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert
|
||||||
// then embedding in certificateList below.
|
// then embedding in certificateList below.
|
||||||
tbsCertList.Raw = tbsCertListContents
|
tbsCertList.Raw = tbsCertListContents
|
||||||
|
|
||||||
input := tbsCertListContents
|
signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand)
|
||||||
if hashFunc != 0 {
|
|
||||||
h := hashFunc.New()
|
|
||||||
h.Write(tbsCertListContents)
|
|
||||||
input = h.Sum(nil)
|
|
||||||
}
|
|
||||||
var signerOpts crypto.SignerOpts = hashFunc
|
|
||||||
if template.SignatureAlgorithm.isRSAPSS() {
|
|
||||||
signerOpts = &rsa.PSSOptions{
|
|
||||||
SaltLength: rsa.PSSSaltLengthEqualsHash,
|
|
||||||
Hash: hashFunc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
signature, err := priv.Sign(rand, input, signerOpts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return asn1.Marshal(certificateList{
|
return asn1.Marshal(certificateList{
|
||||||
TBSCertList: tbsCertList,
|
TBSCertList: tbsCertList,
|
||||||
SignatureAlgorithm: signatureAlgorithm,
|
SignatureAlgorithm: algorithmIdentifier,
|
||||||
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1301,11 +1301,13 @@ func TestCRLCreation(t *testing.T) {
|
||||||
crlBytes, err := test.cert.CreateCRL(rand.Reader, test.priv, revokedCerts, now, expiry)
|
crlBytes, err := test.cert.CreateCRL(rand.Reader, test.priv, revokedCerts, now, expiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: error creating CRL: %s", test.name, err)
|
t.Errorf("%s: error creating CRL: %s", test.name, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedCRL, err := ParseDERCRL(crlBytes)
|
parsedCRL, err := ParseDERCRL(crlBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: error reparsing CRL: %s", test.name, err)
|
t.Errorf("%s: error reparsing CRL: %s", test.name, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, expectedCerts) {
|
if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, expectedCerts) {
|
||||||
t.Errorf("%s: RevokedCertificates mismatch: got %v; want %v.", test.name,
|
t.Errorf("%s: RevokedCertificates mismatch: got %v; want %v.", test.name,
|
||||||
|
|
@ -1815,7 +1817,7 @@ func TestInsecureAlgorithmErrorString(t *testing.T) {
|
||||||
{MD5WithRSA, "x509: cannot verify signature: insecure algorithm MD5-RSA"},
|
{MD5WithRSA, "x509: cannot verify signature: insecure algorithm MD5-RSA"},
|
||||||
{SHA1WithRSA, "x509: cannot verify signature: insecure algorithm SHA1-RSA (temporarily override with GODEBUG=x509sha1=1)"},
|
{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)"},
|
{ECDSAWithSHA1, "x509: cannot verify signature: insecure algorithm ECDSA-SHA1 (temporarily override with GODEBUG=x509sha1=1)"},
|
||||||
{MD2WithRSA, "x509: cannot verify signature: insecure algorithm MD2-RSA"},
|
{MD2WithRSA, "x509: cannot verify signature: insecure algorithm 1"},
|
||||||
{-1, "x509: cannot verify signature: insecure algorithm -1"},
|
{-1, "x509: cannot verify signature: insecure algorithm -1"},
|
||||||
{0, "x509: cannot verify signature: insecure algorithm 0"},
|
{0, "x509: cannot verify signature: insecure algorithm 0"},
|
||||||
{9999, "x509: cannot verify signature: insecure algorithm 9999"},
|
{9999, "x509: cannot verify signature: insecure algorithm 9999"},
|
||||||
|
|
@ -2959,10 +2961,13 @@ func TestRSAPSAParameters(t *testing.T) {
|
||||||
return serialized
|
return serialized
|
||||||
}
|
}
|
||||||
|
|
||||||
for h, params := range hashToPSSParameters {
|
for _, detail := range signatureAlgorithmDetails {
|
||||||
generated := generateParams(h)
|
if !detail.isRSAPSS {
|
||||||
if !bytes.Equal(params.FullBytes, generated) {
|
continue
|
||||||
t.Errorf("hardcoded parameters for %s didn't match generated parameters: got (generated) %x, wanted (hardcoded) %x", h, generated, params.FullBytes)
|
}
|
||||||
|
generated := generateParams(detail.hash)
|
||||||
|
if !bytes.Equal(detail.params.FullBytes, generated) {
|
||||||
|
t.Errorf("hardcoded parameters for %s didn't match generated parameters: got (generated) %x, wanted (hardcoded) %x", detail.hash, generated, detail.params.FullBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3138,15 +3143,11 @@ func TestCreateCertificateBrokenSigner(t *testing.T) {
|
||||||
SerialNumber: big.NewInt(10),
|
SerialNumber: big.NewInt(10),
|
||||||
DNSNames: []string{"example.com"},
|
DNSNames: []string{"example.com"},
|
||||||
}
|
}
|
||||||
k, err := rsa.GenerateKey(rand.Reader, 1024)
|
expectedErr := "signature returned by signer is invalid"
|
||||||
if err != nil {
|
_, err := CreateCertificate(rand.Reader, template, template, testPrivateKey.Public(), &brokenSigner{testPrivateKey.Public()})
|
||||||
t.Fatalf("failed to generate test key: %s", err)
|
|
||||||
}
|
|
||||||
expectedErr := "x509: signature over certificate returned by signer is invalid: crypto/rsa: verification error"
|
|
||||||
_, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected CreateCertificate to fail with a broken signer")
|
t.Fatal("expected CreateCertificate to fail with a broken signer")
|
||||||
} else if err.Error() != expectedErr {
|
} else if !strings.Contains(err.Error(), expectedErr) {
|
||||||
t.Fatalf("CreateCertificate returned an unexpected error: got %q, want %q", err, expectedErr)
|
t.Fatalf("CreateCertificate returned an unexpected error: got %q, want %q", err, expectedErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue