From 992ad55e3dcea4bd017d618d759cb9cd3529f288 Mon Sep 17 00:00:00 2001 From: Filippo Valsorda Date: Wed, 26 Nov 2025 21:11:35 +0100 Subject: [PATCH] crypto/tls: support crypto.MessageSigner private keys Fixes #75656 Change-Id: I6bc71c80973765ef995d17b1450ea2026a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/724820 Auto-Submit: Filippo Valsorda Reviewed-by: Nicholas Husin Reviewed-by: Roland Shoemaker LUCI-TryBot-Result: Go LUCI Reviewed-by: Nicholas Husin --- .../6-stdlib/99-minor/crypto/tls/75656.md | 2 + src/crypto/tls/auth.go | 58 +++++++--- src/crypto/tls/common.go | 7 +- src/crypto/tls/handshake_client.go | 36 +++--- src/crypto/tls/handshake_client_tls13.go | 6 +- src/crypto/tls/handshake_server.go | 18 ++- src/crypto/tls/handshake_server_tls13.go | 6 +- src/crypto/tls/key_agreement.go | 107 +++++++++--------- src/crypto/tls/prf.go | 20 +--- src/crypto/tls/tls_test.go | 71 ++++++++++++ 10 files changed, 214 insertions(+), 117 deletions(-) create mode 100644 doc/next/6-stdlib/99-minor/crypto/tls/75656.md diff --git a/doc/next/6-stdlib/99-minor/crypto/tls/75656.md b/doc/next/6-stdlib/99-minor/crypto/tls/75656.md new file mode 100644 index 0000000000..a2b8d9bf9c --- /dev/null +++ b/doc/next/6-stdlib/99-minor/crypto/tls/75656.md @@ -0,0 +1,2 @@ +If [Certificate.PrivateKey] implements [crypto.MessageSigner], its SignMessage +method is used instead of Sign in TLS 1.2 and later. diff --git a/src/crypto/tls/auth.go b/src/crypto/tls/auth.go index 7169e47105..1b26dd50ef 100644 --- a/src/crypto/tls/auth.go +++ b/src/crypto/tls/auth.go @@ -18,9 +18,13 @@ import ( "slices" ) -// verifyHandshakeSignature verifies a signature against pre-hashed -// (if required) handshake contents. +// verifyHandshakeSignature verifies a signature against unhashed handshake contents. func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error { + if hashFunc != directSigning { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) + } switch sigType { case signatureECDSA: pubKey, ok := pubkey.(*ecdsa.PublicKey) @@ -61,6 +65,32 @@ func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc c return nil } +// verifyLegacyHandshakeSignature verifies a TLS 1.0 and 1.1 signature against +// pre-hashed handshake contents. +func verifyLegacyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, hashed, sig []byte) error { + switch sigType { + case signatureECDSA: + pubKey, ok := pubkey.(*ecdsa.PublicKey) + if !ok { + return fmt.Errorf("expected an ECDSA public key, got %T", pubkey) + } + if !ecdsa.VerifyASN1(pubKey, hashed, sig) { + return errors.New("ECDSA verification failure") + } + case signaturePKCS1v15: + pubKey, ok := pubkey.(*rsa.PublicKey) + if !ok { + return fmt.Errorf("expected an RSA public key, got %T", pubkey) + } + if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, hashed, sig); err != nil { + return err + } + default: + return errors.New("internal error: unknown signature type") + } + return nil +} + const ( serverSignatureContext = "TLS 1.3, server CertificateVerify\x00" clientSignatureContext = "TLS 1.3, client CertificateVerify\x00" @@ -77,21 +107,15 @@ var signaturePadding = []byte{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, } -// signedMessage returns the pre-hashed (if necessary) message to be signed by -// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3. -func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte { - if sigHash == directSigning { - b := &bytes.Buffer{} - b.Write(signaturePadding) - io.WriteString(b, context) - b.Write(transcript.Sum(nil)) - return b.Bytes() - } - h := sigHash.New() - h.Write(signaturePadding) - io.WriteString(h, context) - h.Write(transcript.Sum(nil)) - return h.Sum(nil) +// signedMessage returns the (unhashed) message to be signed by certificate keys +// in TLS 1.3. See RFC 8446, Section 4.4.3. +func signedMessage(context string, transcript hash.Hash) []byte { + const maxSize = 64 /* signaturePadding */ + len(serverSignatureContext) + 512/8 /* SHA-512 */ + b := bytes.NewBuffer(make([]byte, 0, maxSize)) + b.Write(signaturePadding) + io.WriteString(b, context) + b.Write(transcript.Sum(nil)) + return b.Bytes() } // typeAndHashFromSignatureScheme returns the corresponding signature type and diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 993cfaf7c0..099a11ca63 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -1597,9 +1597,14 @@ var writerMutex sync.Mutex type Certificate struct { Certificate [][]byte // PrivateKey contains the private key corresponding to the public key in - // Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey. + // Leaf. This must implement [crypto.Signer] with an RSA, ECDSA or Ed25519 + // PublicKey. + // // For a server up to TLS 1.2, it can also implement crypto.Decrypter with // an RSA PublicKey. + // + // If it implements [crypto.MessageSigner], SignMessage will be used instead + // of Sign for TLS 1.2 and later. PrivateKey crypto.PrivateKey // SupportedSignatureAlgorithms is an optional list restricting what // signature algorithms the PrivateKey can be used for. diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index e1ddcb3f10..c2b1b7037a 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -781,15 +781,13 @@ func (hs *clientHandshakeState) doFullHandshake() error { return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) } - var sigType uint8 - var sigHash crypto.Hash if c.vers >= VersionTLS12 { signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms) if err != nil { c.sendAlert(alertHandshakeFailure) return err } - sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm) + sigType, sigHash, err := typeAndHashFromSignatureScheme(signatureAlgorithm) if err != nil { return c.sendAlert(alertInternalError) } @@ -799,23 +797,31 @@ func (hs *clientHandshakeState) doFullHandshake() error { tlssha1.Value() // ensure godebug is initialized tlssha1.IncNonDefault() } + if hs.finishedHash.buffer == nil { + c.sendAlert(alertInternalError) + return errors.New("tls: internal error: did not keep handshake transcript for TLS 1.2") + } + signOpts := crypto.SignerOpts(sigHash) + if sigType == signatureRSAPSS { + signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} + } + certVerify.signature, err = crypto.SignMessage(key, c.config.rand(), hs.finishedHash.buffer, signOpts) + if err != nil { + c.sendAlert(alertInternalError) + return err + } } else { - sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public()) + sigType, sigHash, err := legacyTypeAndHashFromPublicKey(key.Public()) if err != nil { c.sendAlert(alertIllegalParameter) return err } - } - - signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash) - signOpts := crypto.SignerOpts(sigHash) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts) - if err != nil { - c.sendAlert(alertInternalError) - return err + signed := hs.finishedHash.hashForClientCertificate(sigType) + certVerify.signature, err = key.Sign(c.config.rand(), signed, sigHash) + if err != nil { + c.sendAlert(alertInternalError) + return err + } } if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil { diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go index 2912d97f75..e696bd3a13 100644 --- a/src/crypto/tls/handshake_client_tls13.go +++ b/src/crypto/tls/handshake_client_tls13.go @@ -664,7 +664,7 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error { if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { return c.sendAlert(alertInternalError) } - signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) + signed := signedMessage(serverSignatureContext, hs.transcript) if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey, sigHash, signed, certVerify.signature); err != nil { c.sendAlert(alertDecryptError) @@ -783,12 +783,12 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { return c.sendAlert(alertInternalError) } - signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) + signed := signedMessage(clientSignatureContext, hs.transcript) signOpts := crypto.SignerOpts(sigHash) if sigType == signatureRSAPSS { signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} } - sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) + sig, err := crypto.SignMessage(cert.PrivateKey.(crypto.Signer), c.config.rand(), signed, signOpts) if err != nil { c.sendAlert(alertInternalError) return errors.New("tls: failed to sign handshake: " + err.Error()) diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index 2d3efffcf0..efdaeae6f7 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -780,19 +780,27 @@ func (hs *serverHandshakeState) doFullHandshake() error { tlssha1.Value() // ensure godebug is initialized tlssha1.IncNonDefault() } + if hs.finishedHash.buffer == nil { + c.sendAlert(alertInternalError) + return errors.New("tls: internal error: did not keep handshake transcript for TLS 1.2") + } + if err := verifyHandshakeSignature(sigType, pub, sigHash, hs.finishedHash.buffer, certVerify.signature); err != nil { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid signature by the client certificate: " + err.Error()) + } } else { sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub) if err != nil { c.sendAlert(alertIllegalParameter) return err } + signed := hs.finishedHash.hashForClientCertificate(sigType) + if err := verifyLegacyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil { + c.sendAlert(alertDecryptError) + return errors.New("tls: invalid signature by the client certificate: " + err.Error()) + } } - signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash) - if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil { - c.sendAlert(alertDecryptError) - return errors.New("tls: invalid signature by the client certificate: " + err.Error()) - } c.peerSigAlg = certVerify.signatureAlgorithm if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil { diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go index 1182307936..3bed1359a3 100644 --- a/src/crypto/tls/handshake_server_tls13.go +++ b/src/crypto/tls/handshake_server_tls13.go @@ -845,12 +845,12 @@ func (hs *serverHandshakeStateTLS13) sendServerCertificate() error { return c.sendAlert(alertInternalError) } - signed := signedMessage(sigHash, serverSignatureContext, hs.transcript) + signed := signedMessage(serverSignatureContext, hs.transcript) signOpts := crypto.SignerOpts(sigHash) if sigType == signatureRSAPSS { signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} } - sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts) + sig, err := crypto.SignMessage(hs.cert.PrivateKey.(crypto.Signer), c.config.rand(), signed, signOpts) if err != nil { public := hs.cert.PrivateKey.(crypto.Signer).Public() if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS && @@ -1081,7 +1081,7 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error { if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 { return c.sendAlert(alertInternalError) } - signed := signedMessage(sigHash, clientSignatureContext, hs.transcript) + signed := signedMessage(clientSignatureContext, hs.transcript) if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey, sigHash, signed, certVerify.signature); err != nil { c.sendAlert(alertDecryptError) diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go index 26f7bd2c52..ad2be5ddf9 100644 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@ -127,25 +127,8 @@ func md5SHA1Hash(slices [][]byte) []byte { } // hashForServerKeyExchange hashes the given slices and returns their digest -// using the given hash function (for TLS 1.2) or using a default based on -// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't -// do pre-hashing, it returns the concatenation of the slices. -func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte { - if sigType == signatureEd25519 { - var signed []byte - for _, slice := range slices { - signed = append(signed, slice...) - } - return signed - } - if version >= VersionTLS12 { - h := hashFunc.New() - for _, slice := range slices { - h.Write(slice) - } - digest := h.Sum(nil) - return digest - } +// using a hash based on the sigType. It can only be used for TLS 1.0 and 1.1. +func hashForServerKeyExchange(sigType uint8, slices ...[]byte) []byte { if sigType == signatureECDSA { return sha1Hash(slices) } @@ -207,14 +190,13 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey) } - var sigType uint8 - var sigHash crypto.Hash + var sig []byte if ka.version >= VersionTLS12 { ka.signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms) if err != nil { return nil, err } - sigType, sigHash, err = typeAndHashFromSignatureScheme(ka.signatureAlgorithm) + sigType, sigHash, err := typeAndHashFromSignatureScheme(ka.signatureAlgorithm) if err != nil { return nil, err } @@ -222,25 +204,31 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer tlssha1.Value() // ensure godebug is initialized tlssha1.IncNonDefault() } + signed := slices.Concat(clientHello.random, hello.random, serverECDHEParams) + if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { + return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") + } + signOpts := crypto.SignerOpts(sigHash) + if sigType == signatureRSAPSS { + signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} + } + sig, err = crypto.SignMessage(priv, config.rand(), signed, signOpts) + if err != nil { + return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) + } } else { - sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public()) + sigType, sigHash, err := legacyTypeAndHashFromPublicKey(priv.Public()) if err != nil { return nil, err } - } - if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { - return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") - } - - signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams) - - signOpts := crypto.SignerOpts(sigHash) - if sigType == signatureRSAPSS { - signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash} - } - sig, err := priv.Sign(config.rand(), signed, signOpts) - if err != nil { - return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) + signed := hashForServerKeyExchange(sigType, clientHello.random, hello.random, serverECDHEParams) + if (sigType == signaturePKCS1v15) != ka.isRSA { + return nil, errors.New("tls: certificate cannot be used with the selected cipher suite") + } + sig, err = priv.Sign(config.rand(), signed, sigHash) + if err != nil { + return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error()) + } } skx := new(serverKeyExchangeMsg) @@ -300,6 +288,18 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell if len(sig) < 2 { return errServerKeyExchange } + if ka.version >= VersionTLS12 { + ka.signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) + sig = sig[2:] + if len(sig) < 2 { + return errServerKeyExchange + } + } + sigLen := int(sig[0])<<8 | int(sig[1]) + if sigLen+2 != len(sig) { + return errServerKeyExchange + } + sig = sig[2:] if !slices.Contains(clientHello.supportedCurves, ka.curveID) { return errors.New("tls: server selected unoffered curve") @@ -333,12 +333,6 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell var sigType uint8 var sigHash crypto.Hash if ka.version >= VersionTLS12 { - ka.signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1]) - sig = sig[2:] - if len(sig) < 2 { - return errServerKeyExchange - } - if !isSupportedSignatureAlgorithm(ka.signatureAlgorithm, clientHello.supportedSignatureAlgorithms) { return errors.New("tls: certificate used with invalid signature algorithm") } @@ -350,26 +344,27 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell tlssha1.Value() // ensure godebug is initialized tlssha1.IncNonDefault() } + if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { + return errServerKeyExchange + } + signed := slices.Concat(clientHello.random, serverHello.random, serverECDHEParams) + if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil { + return errors.New("tls: invalid signature by the server certificate: " + err.Error()) + } } else { sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey) if err != nil { return err } + if (sigType == signaturePKCS1v15) != ka.isRSA { + return errServerKeyExchange + } + signed := hashForServerKeyExchange(sigType, clientHello.random, serverHello.random, serverECDHEParams) + if err := verifyLegacyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil { + return errors.New("tls: invalid signature by the server certificate: " + err.Error()) + } } - if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA { - return errServerKeyExchange - } - - sigLen := int(sig[0])<<8 | int(sig[1]) - if sigLen+2 != len(sig) { - return errServerKeyExchange - } - sig = sig[2:] - signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams) - if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil { - return errors.New("tls: invalid signature by the server certificate: " + err.Error()) - } return nil } diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go index e7369542a7..19f80ac2c9 100644 --- a/src/crypto/tls/prf.go +++ b/src/crypto/tls/prf.go @@ -221,23 +221,9 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { return h.prf(masterSecret, serverFinishedLabel, h.Sum(), finishedVerifyLength) } -// hashForClientCertificate returns the handshake messages so far, pre-hashed if -// necessary, suitable for signing by a TLS client certificate. -func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash) []byte { - if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil { - panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer") - } - - if sigType == signatureEd25519 { - return h.buffer - } - - if h.version >= VersionTLS12 { - hash := hashAlg.New() - hash.Write(h.buffer) - return hash.Sum(nil) - } - +// hashForClientCertificate returns the handshake messages so far, pre-hashed, +// suitable for signing by a TLS 1.0 and 1.1 client certificate. +func (h finishedHash) hashForClientCertificate(sigType uint8) []byte { if sigType == signatureECDSA { return h.server.Sum(nil) } diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go index af2828fd8d..39ebb9d2f1 100644 --- a/src/crypto/tls/tls_test.go +++ b/src/crypto/tls/tls_test.go @@ -2390,3 +2390,74 @@ func TestECH(t *testing.T) { check() } + +func TestMessageSigner(t *testing.T) { + t.Run("TLSv10", func(t *testing.T) { testMessageSigner(t, VersionTLS10) }) + t.Run("TLSv12", func(t *testing.T) { testMessageSigner(t, VersionTLS12) }) + t.Run("TLSv13", func(t *testing.T) { testMessageSigner(t, VersionTLS13) }) +} + +func testMessageSigner(t *testing.T, version uint16) { + clientConfig, serverConfig := testConfig.Clone(), testConfig.Clone() + serverConfig.ClientAuth = RequireAnyClientCert + clientConfig.MinVersion = version + clientConfig.MaxVersion = version + serverConfig.MinVersion = version + serverConfig.MaxVersion = version + clientConfig.Certificates = []Certificate{{ + Certificate: [][]byte{testRSACertificate}, + PrivateKey: messageOnlySigner{testRSAPrivateKey}, + }} + serverConfig.Certificates = []Certificate{{ + Certificate: [][]byte{testRSACertificate}, + PrivateKey: messageOnlySigner{testRSAPrivateKey}, + }} + + _, _, err := testHandshake(t, clientConfig, serverConfig) + if version < VersionTLS12 { + if err == nil { + t.Fatal("expected failure for TLS 1.0/1.1") + } + } else { + if err != nil { + t.Fatalf("unexpected failure: %s", err) + } + } + + clientConfig.Certificates = []Certificate{{ + Certificate: [][]byte{testECDSACertificate}, + PrivateKey: messageOnlySigner{testECDSAPrivateKey}, + }} + serverConfig.Certificates = []Certificate{{ + Certificate: [][]byte{testECDSACertificate}, + PrivateKey: messageOnlySigner{testECDSAPrivateKey}, + }} + + _, _, err = testHandshake(t, clientConfig, serverConfig) + if version < VersionTLS12 { + if err == nil { + t.Fatal("expected failure for TLS 1.0/1.1") + } + } else { + if err != nil { + t.Fatalf("unexpected failure: %s", err) + } + } +} + +type messageOnlySigner struct{ crypto.Signer } + +func (s messageOnlySigner) Public() crypto.PublicKey { + return s.Signer.Public() +} + +func (s messageOnlySigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { + return nil, errors.New("messageOnlySigner: Sign called") +} + +func (s messageOnlySigner) SignMessage(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { + h := opts.HashFunc().New() + h.Write(msg) + digest := h.Sum(nil) + return s.Signer.Sign(rand, digest, opts) +} -- 2.52.0