From 9f46cf9e2d51100051099b5151d9dca7d836da9f Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 22 Nov 2017 19:27:20 +0000 Subject: [PATCH] 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 --- auth.go | 17 +++++++++++++---- cipher_suites.go | 4 ++-- common.go | 9 ++++++--- handshake_client.go | 6 +++++- key_agreement.go | 14 +++++++++----- prf.go | 2 +- 6 files changed, 36 insertions(+), 16 deletions(-) diff --git a/auth.go b/auth.go index 1e0cf23..742013b 100644 --- a/auth.go +++ b/auth.go @@ -26,9 +26,9 @@ func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []S switch pubkey.(type) { case *rsa.PublicKey: if tlsVersion < VersionTLS12 { - return 0, signatureRSA, crypto.MD5SHA1, nil + return 0, signaturePKCS1v15, crypto.MD5SHA1, nil } else { - return PKCS1WithSHA1, signatureRSA, crypto.SHA1, nil + return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil } case *ecdsa.PublicKey: return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil @@ -47,7 +47,7 @@ func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []S sigType := signatureFromSignatureScheme(sigAlg) switch pubkey.(type) { case *rsa.PublicKey: - if sigType == signatureRSA { + if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS { return sigAlg, sigType, hashAlg, nil } 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) { return errors.New("tls: ECDSA verification failure") } - case signatureRSA: + case signaturePKCS1v15: pubKey, ok := pubkey.(*rsa.PublicKey) if !ok { 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 { 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: return errors.New("tls: unknown signature algorithm") } diff --git a/cipher_suites.go b/cipher_suites.go index 8791406..26dc92d 100644 --- a/cipher_suites.go +++ b/cipher_suites.go @@ -356,14 +356,14 @@ func rsaKA(version uint16) keyAgreement { func ecdheECDSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ - sigType: signatureECDSA, + isRSA: false, version: version, } } func ecdheRSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ - sigType: signatureRSA, + isRSA: true, version: version, } } diff --git a/common.go b/common.go index 871e338..80bab19 100644 --- a/common.go +++ b/common.go @@ -164,8 +164,9 @@ const ( // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) const ( - signatureRSA uint8 = 1 - signatureECDSA uint8 = 3 + signaturePKCS1v15 uint8 = iota + 1 + signatureECDSA + signatureRSAPSS ) // supportedSignatureAlgorithms contains the signature and hash algorithms that @@ -1156,7 +1157,9 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 { switch signatureAlgorithm { case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: - return signatureRSA + return signaturePKCS1v15 + case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512: + return signatureRSAPSS case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: return signatureECDSA default: diff --git a/handshake_client.go b/handshake_client.go index e904518..9f4d113 100644 --- a/handshake_client.go +++ b/handshake_client.go @@ -499,7 +499,11 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.sendAlert(alertInternalError) 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 { c.sendAlert(alertInternalError) return err diff --git a/key_agreement.go b/key_agreement.go index d161fe8..1c5660d 100644 --- a/key_agreement.go +++ b/key_agreement.go @@ -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 // pre-master secret is then calculated using ECDH. The signature may // either be ECDSA or RSA. type ecdheKeyAgreement struct { version uint16 - sigType uint8 + isRSA bool privateKey []byte curveid CurveID @@ -216,7 +216,7 @@ NextCandidate: if err != nil { 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") } @@ -226,7 +226,11 @@ NextCandidate: } 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 { 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 { return err } - if sigType != ka.sigType { + if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { return errServerKeyExchange } diff --git a/prf.go b/prf.go index 53cf04a..0751909 100644 --- a/prf.go +++ b/prf.go @@ -317,7 +317,7 @@ func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Has } if h.version == VersionSSL30 { - if sigType != signatureRSA { + if sigType != signaturePKCS1v15 { return nil, errors.New("tls: unsupported signature type for client certificate") }