crypto/tls: add RSASSA-PSS support for handshake messages

This adds support for RSASSA-PSS signatures in handshake messages as
required by TLS 1.3. Even if TLS 1.2 is negotiated, it must support PSS
when advertised in the Client Hello (this will be done later as the
testdata will change).

Updates #9671

Change-Id: I8006b92e017453ae408c153233ce5ccef99b5c3f
This commit is contained in:
Peter Wu 2017-11-22 19:27:20 +00:00
parent 1850fd015e
commit 9f46cf9e2d
6 changed files with 36 additions and 16 deletions

17
auth.go
View File

@ -26,9 +26,9 @@ func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []S
switch pubkey.(type) { switch pubkey.(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
if tlsVersion < VersionTLS12 { if tlsVersion < VersionTLS12 {
return 0, signatureRSA, crypto.MD5SHA1, nil return 0, signaturePKCS1v15, crypto.MD5SHA1, nil
} else { } else {
return PKCS1WithSHA1, signatureRSA, crypto.SHA1, nil return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil
} }
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil
@ -47,7 +47,7 @@ func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []S
sigType := signatureFromSignatureScheme(sigAlg) sigType := signatureFromSignatureScheme(sigAlg)
switch pubkey.(type) { switch pubkey.(type) {
case *rsa.PublicKey: case *rsa.PublicKey:
if sigType == signatureRSA { if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS {
return sigAlg, sigType, hashAlg, nil return sigAlg, sigType, hashAlg, nil
} }
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
@ -78,7 +78,7 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c
if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) { if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
return errors.New("tls: ECDSA verification failure") return errors.New("tls: ECDSA verification failure")
} }
case signatureRSA: case signaturePKCS1v15:
pubKey, ok := pubkey.(*rsa.PublicKey) pubKey, ok := pubkey.(*rsa.PublicKey)
if !ok { if !ok {
return errors.New("tls: RSA signing requires a RSA public key") return errors.New("tls: RSA signing requires a RSA public key")
@ -86,6 +86,15 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c
if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil { if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
return err return err
} }
case signatureRSAPSS:
pubKey, ok := pubkey.(*rsa.PublicKey)
if !ok {
return errors.New("tls: RSA signing requires a RSA public key")
}
signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
if err := rsa.VerifyPSS(pubKey, hashFunc, digest, sig, signOpts); err != nil {
return err
}
default: default:
return errors.New("tls: unknown signature algorithm") return errors.New("tls: unknown signature algorithm")
} }

View File

@ -356,14 +356,14 @@ func rsaKA(version uint16) keyAgreement {
func ecdheECDSAKA(version uint16) keyAgreement { func ecdheECDSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{ return &ecdheKeyAgreement{
sigType: signatureECDSA, isRSA: false,
version: version, version: version,
} }
} }
func ecdheRSAKA(version uint16) keyAgreement { func ecdheRSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{ return &ecdheKeyAgreement{
sigType: signatureRSA, isRSA: true,
version: version, version: version,
} }
} }

View File

@ -164,8 +164,9 @@ const (
// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
const ( const (
signatureRSA uint8 = 1 signaturePKCS1v15 uint8 = iota + 1
signatureECDSA uint8 = 3 signatureECDSA
signatureRSAPSS
) )
// supportedSignatureAlgorithms contains the signature and hash algorithms that // supportedSignatureAlgorithms contains the signature and hash algorithms that
@ -1156,7 +1157,9 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg
func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 { func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 {
switch signatureAlgorithm { switch signatureAlgorithm {
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
return signatureRSA return signaturePKCS1v15
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
return signatureRSAPSS
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
return signatureECDSA return signatureECDSA
default: default:

View File

@ -499,7 +499,11 @@ func (hs *clientHandshakeState) doFullHandshake() error {
c.sendAlert(alertInternalError) c.sendAlert(alertInternalError)
return err return err
} }
certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc) signOpts := crypto.SignerOpts(hashFunc)
if sigType == signatureRSAPSS {
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
}
certVerify.signature, err = key.Sign(c.config.rand(), digest, signOpts)
if err != nil { if err != nil {
c.sendAlert(alertInternalError) c.sendAlert(alertInternalError)
return err return err

View File

@ -138,13 +138,13 @@ func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
} }
// ecdheRSAKeyAgreement implements a TLS key agreement where the server // ecdheKeyAgreement implements a TLS key agreement where the server
// generates an ephemeral EC public/private key pair and signs it. The // generates an ephemeral EC public/private key pair and signs it. The
// pre-master secret is then calculated using ECDH. The signature may // pre-master secret is then calculated using ECDH. The signature may
// either be ECDSA or RSA. // either be ECDSA or RSA.
type ecdheKeyAgreement struct { type ecdheKeyAgreement struct {
version uint16 version uint16
sigType uint8 isRSA bool
privateKey []byte privateKey []byte
curveid CurveID curveid CurveID
@ -216,7 +216,7 @@ NextCandidate:
if err != nil { if err != nil {
return nil, err return nil, err
} }
if sigType != ka.sigType { if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
} }
@ -226,7 +226,11 @@ NextCandidate:
} }
var sig []byte var sig []byte
sig, err = priv.Sign(config.rand(), digest, hashFunc) signOpts := crypto.SignerOpts(hashFunc)
if sigType == signatureRSAPSS {
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
}
sig, err = priv.Sign(config.rand(), digest, signOpts)
if err != nil { if err != nil {
return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
} }
@ -337,7 +341,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if err != nil { if err != nil {
return err return err
} }
if sigType != ka.sigType { if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
return errServerKeyExchange return errServerKeyExchange
} }

2
prf.go
View File

@ -317,7 +317,7 @@ func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Has
} }
if h.version == VersionSSL30 { if h.version == VersionSSL30 {
if sigType != signatureRSA { if sigType != signaturePKCS1v15 {
return nil, errors.New("tls: unsupported signature type for client certificate") return nil, errors.New("tls: unsupported signature type for client certificate")
} }