golang/go · error
tls: invalid signature by the client certificate: %s
Error message
tls: invalid signature by the client certificate: %s
What it means
The server failed to verify the client's CertificateVerify signature using verifyHandshakeSignature with the client certificate's public key. The underlying error (appended via %s) indicates the specific verification failure: bad signature bytes, wrong hash, or key/signature mismatch. This means the client's signature over the handshake transcript did not validate against the public key in the client certificate.
Source
Thrown at src/crypto/tls/handshake_server_tls13.go:1104
// We don't use certReq.supportedSignatureAlgorithms because it would
// require keeping the certificateRequestMsgTLS13 around in the hs.
if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms(c.vers, c.vers)) ||
!isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, signatureSchemesForPublicKey(c.vers, c.peerCertificates[0].PublicKey)) {
c.sendAlert(alertIllegalParameter)
return errors.New("tls: client certificate used with invalid signature algorithm")
}
sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
if err != nil {
return c.sendAlert(alertInternalError)
}
if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
return c.sendAlert(alertInternalError)
}
signed := signedMessage(clientSignatureContext, hs.transcript)
if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
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.transcript); err != nil {
return err
}
}
// If we waited until the client certificates to send session tickets, we
// are ready to do it now.
if err := hs.sendSessionTickets(); err != nil {
return err
}
return nil
}
func (hs *serverHandshakeStateTLS13) readClientFinished() error {View on GitHub (pinned to b6b368adc5)
Solutions
- Verify the client certificate and private key are a matching pair (openssl x509 -noout -modulus vs openssl rsa -noout -modulus for RSA).
- Check for any proxy/MITM that could alter handshake messages between client and server.
- If using a hardware token/smart card, verify it correctly signs the TLS transcript.
- Update the client TLS library — older versions may compute the transcript hash incorrectly.
- Compare the client's signature input (transcript hash) against what the server expects.
Example fix
// Verify cert/key match (on the client side) // For RSA certs: // openssl x509 -noout -modulus -in client.crt | openssl md5 // openssl rsa -noout -modulus -in client.key | openssl md5 // Both must produce identical output. // If they differ, regenerate the certificate from the correct key.
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify cert/key match before using them
func verifyCertKeyPair(cert *x509.Certificate, key crypto.PrivateKey) error {
switch pub := cert.PublicKey.(type) {
case *rsa.PublicKey:
rsaKey, ok := key.(*rsa.PrivateKey)
if !ok || pub.N.Cmp(rsaKey.N) != 0 {
return errors.New("RSA certificate and key do not match")
}
case *ecdsa.PublicKey:
ecKey, ok := key.(*ecdsa.PrivateKey)
if !ok || pub.X.Cmp(ecKey.X) != 0 {
return errors.New("ECDSA certificate and key do not match")
}
case ed25519.PublicKey:
edKey, ok := key.(ed25519.PrivateKey)
if !ok || !bytes.Equal(pub, edKey.Public().(ed25519.PublicKey)) {
return errors.New("Ed25519 certificate and key do not match")
}
}
return nil
} Try / catch
// Server-side: handle during mTLS handshake
if err := conn.Handshake(); err != nil {
if strings.Contains(err.Error(), "invalid signature by the client certificate") {
log.Printf("client cert signature verification failed: %v", err)
}
} Prevention
- Verify client cert/key pair consistency before distribution.
- Test mTLS client auth end-to-end with known-good certs.
- Monitor for MITM interference if signature errors appear unexpectedly.
- Use modern, well-tested client TLS libraries.
When it happens
Trigger: Server is performing mTLS client cert authentication. The client sent a CertificateVerify message whose signature doesn't match: could be a corrupted signature in transit, a client signing the wrong data (wrong transcript hash), a mismatched key pair (cert doesn't match the signing key), or a man-in-the-middle altering the handshake.
Common situations: Client cert/key mismatch (cert was reissued but old key is used); MITM proxy altering handshake messages; client library bug in computing the transcript hash to sign; hardware token (smart card) signing failure that produces invalid output; client using a different TLS implementation for signing vs. cert generation.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: client certificate used with invalid signature algorith
- tls: client sent encrypted_client_hello extension with unsup
- tls: client sent encrypted_client_hello extension but did no
- tls: invalid signature by the client certificate: {err}
- tls: client didn't provide a certificate
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/d9d0daee29d86094.
Report an issue: GitHub.