)
func (algo SignatureAlgorithm) isRSAPSS() bool {
- switch algo {
- case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
- return true
- default:
- return false
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == algo {
+ return details.isRSAPSS
+ }
}
+ 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 {
//
// RFC 3279 2.2.1 RSA Signature Algorithms
//
-// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
-//
// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
//
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
//
// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
var (
- oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
algo SignatureAlgorithm
name string
oid asn1.ObjectIdentifier
+ params asn1.RawValue
pubKeyAlgo PublicKeyAlgorithm
hash crypto.Hash
+ isRSAPSS bool
}{
- {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
- {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5},
- {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
- {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
- {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
- {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
- {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
- {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256},
- {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384},
- {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512},
- {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
- {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
- {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
- {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
- {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
- {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
- {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
-}
-
-// hashToPSSParameters contains the DER encoded RSA PSS parameters for the
+ {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false},
+ {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
+ {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
+ {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false},
+ {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false},
+ {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false},
+ {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true},
+ {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true},
+ {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true},
+ {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false},
+ {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false},
+ {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false},
+ {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false},
+ {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false},
+ {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false},
+ {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false},
+}
+
+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.
// The parameters contain the following values:
// - hashAlgorithm contains the associated hash identifier with NULL parameters
// - maskGenAlgorithm always contains the default mgf1SHA1 identifier
// - saltLength contains the length of the associated hash
// - trailerField always contains the default trailerFieldBC value
-var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
- 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}},
- 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}},
- 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}},
-}
+var (
+ 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}}
+ 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}}
+ 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
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
return asn1.Marshal(cert.Subject.ToRDNSequence())
}
-// signingParamsForPublicKey returns the parameters to use for signing with
-// priv. If requestedSigAlgo is not zero then it overrides the default
-// signature algorithm.
-func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+// signingParamsForKey returns the signature algorithm and its Algorithm
+// Identifier to use for signing, based on the key type. If sigAlgo is not zero
+// then it overrides the default.
+func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) {
+ var ai pkix.AlgorithmIdentifier
var pubType PublicKeyAlgorithm
+ var defaultAlgo SignatureAlgorithm
- switch pub := pub.(type) {
+ switch pub := key.Public().(type) {
case *rsa.PublicKey:
pubType = RSA
- hashFunc = crypto.SHA256
- sigAlgo.Algorithm = oidSignatureSHA256WithRSA
- sigAlgo.Parameters = asn1.NullRawValue
+ defaultAlgo = SHA256WithRSA
case *ecdsa.PublicKey:
pubType = ECDSA
-
switch pub.Curve {
case elliptic.P224(), elliptic.P256():
- hashFunc = crypto.SHA256
- sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+ defaultAlgo = ECDSAWithSHA256
case elliptic.P384():
- hashFunc = crypto.SHA384
- sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+ defaultAlgo = ECDSAWithSHA384
case elliptic.P521():
- hashFunc = crypto.SHA512
- sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+ defaultAlgo = ECDSAWithSHA512
default:
- err = errors.New("x509: unknown elliptic curve")
+ return 0, ai, errors.New("x509: unsupported elliptic curve")
}
case ed25519.PublicKey:
pubType = Ed25519
- sigAlgo.Algorithm = oidSignatureEd25519
+ defaultAlgo = PureEd25519
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 {
- return
- }
-
- if requestedSigAlgo == 0 {
- return
+ if sigAlgo == 0 {
+ sigAlgo = defaultAlgo
}
- found := false
for _, details := range signatureAlgorithmDetails {
- if details.algo == requestedSigAlgo {
+ if details.algo == sigAlgo {
if details.pubKeyAlgo != pubType {
- err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
- return
- }
- sigAlgo.Algorithm, hashFunc = details.oid, details.hash
- if hashFunc == 0 && pubType != Ed25519 {
- err = errors.New("x509: cannot sign with hash function requested")
- return
+ return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type")
}
- if hashFunc == crypto.MD5 {
- err = errors.New("x509: signing with MD5 is not supported")
- return
+ if details.hash == crypto.MD5 {
+ return 0, ai, errors.New("x509: signing with MD5 is not supported")
}
- if requestedSigAlgo.isRSAPSS() {
- sigAlgo.Parameters = hashToPSSParameters[hashFunc]
- }
- found = true
- break
+
+ return sigAlgo, pkix.AlgorithmIdentifier{
+ Algorithm: details.oid,
+ Parameters: details.params,
+ }, nil
}
}
- if !found {
- err = errors.New("x509: unknown SignatureAlgorithm")
+ return 0, ai, errors.New("x509: unknown SignatureAlgorithm")
+}
+
+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)
}
- return
+ 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
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 {
return nil, err
}
c := tbsCertificate{
Version: 2,
SerialNumber: template.SerialNumber,
- SignatureAlgorithm: signatureAlgorithm,
+ SignatureAlgorithm: algorithmIdentifier,
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
Subject: asn1.RawValue{FullBytes: asn1Subject},
}
c.Raw = tbsCertContents
- signed := tbsCertContents
- 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)
+ signature, err := signTBS(tbsCertContents, key, signatureAlgorithm, rand)
if err != nil {
return nil, err
}
- signedCert, err := asn1.Marshal(certificate{
- c,
- signatureAlgorithm,
- asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ return asn1.Marshal(certificate{
+ TBSCertificate: c,
+ SignatureAlgorithm: algorithmIdentifier,
+ 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
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 {
return nil, err
}
tbsCertList := pkix.TBSCertificateList{
Version: 1,
- Signature: signatureAlgorithm,
+ Signature: algorithmIdentifier,
Issuer: c.Subject.ToRDNSequence(),
ThisUpdate: now.UTC(),
NextUpdate: expiry.UTC(),
aki.Id = oidExtensionAuthorityKeyId
aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
if err != nil {
- return
+ return nil, err
}
tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
}
tbsCertListContents, err := asn1.Marshal(tbsCertList)
if err != nil {
- return
- }
-
- signed := tbsCertListContents
- if hashFunc != 0 {
- h := hashFunc.New()
- h.Write(signed)
- signed = h.Sum(nil)
+ return nil, err
}
+ tbsCertList.Raw = tbsCertListContents
- var signature []byte
- signature, err = key.Sign(rand, signed, hashFunc)
+ signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand)
if err != nil {
- return
+ return nil, err
}
return asn1.Marshal(pkix.CertificateList{
TBSCertList: tbsCertList,
- SignatureAlgorithm: signatureAlgorithm,
+ SignatureAlgorithm: algorithmIdentifier,
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
- var hashFunc crypto.Hash
- var sigAlgo pkix.AlgorithmIdentifier
- hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+ signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm)
if err != nil {
return nil, err
}
rawAttributes, err := newRawAttributes(attributes)
if err != nil {
- return
+ return nil, err
}
// If not included in attributes, add a new attribute for the
tbsCSRContents, err := asn1.Marshal(tbsCSR)
if err != nil {
- return
+ return nil, err
}
tbsCSR.Raw = tbsCSRContents
- signed := tbsCSRContents
- 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)
+ signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand)
if err != nil {
- return
+ return nil, err
}
return asn1.Marshal(certificateRequest{
TBSCSR: tbsCSR,
- SignatureAlgorithm: sigAlgo,
- SignatureValue: asn1.BitString{
- Bytes: signature,
- BitLength: len(signature) * 8,
- },
+ SignatureAlgorithm: algorithmIdentifier,
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
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 {
return nil, err
}
tbsCertList := tbsCertificateList{
Version: 1, // v2
- Signature: signatureAlgorithm,
+ Signature: algorithmIdentifier,
Issuer: asn1.RawValue{FullBytes: issuerSubject},
ThisUpdate: template.ThisUpdate.UTC(),
NextUpdate: template.NextUpdate.UTC(),
// then embedding in certificateList below.
tbsCertList.Raw = tbsCertListContents
- input := tbsCertListContents
- 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)
+ signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand)
if err != nil {
return nil, err
}
return asn1.Marshal(certificateList{
TBSCertList: tbsCertList,
- SignatureAlgorithm: signatureAlgorithm,
+ SignatureAlgorithm: algorithmIdentifier,
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}