{"record":{"id":"3508a6de6bee4b19","repo":"golang/go","slug":"tls-invalid-signature-by-the-client-certificate","errorCode":null,"errorMessage":"tls: invalid signature by the client certificate: {err}","messagePattern":"tls: invalid signature by the client certificate: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_server.go","lineNumber":797,"sourceCode":"\t\t\tif !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {\n\t\t\t\tc.sendAlert(alertIllegalParameter)\n\t\t\t\treturn errors.New(\"tls: client certificate used with invalid signature algorithm\")\n\t\t\t}\n\t\t\tsigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)\n\t\t\tif err != nil {\n\t\t\t\treturn c.sendAlert(alertInternalError)\n\t\t\t}\n\t\t\tif sigHash == crypto.SHA1 {\n\t\t\t\ttlssha1.Value() // ensure godebug is initialized\n\t\t\t\ttlssha1.IncNonDefault()\n\t\t\t}\n\t\t\tif hs.finishedHash.buffer == nil {\n\t\t\t\tc.sendAlert(alertInternalError)\n\t\t\t\treturn errors.New(\"tls: internal error: did not keep handshake transcript for TLS 1.2\")\n\t\t\t}\n\t\t\tif err := verifyHandshakeSignature(sigType, pub, sigHash, hs.finishedHash.buffer, certVerify.signature); err != nil {\n\t\t\t\tc.sendAlert(alertDecryptError)\n\t\t\t\treturn errors.New(\"tls: invalid signature by the client certificate: \" + err.Error())\n\t\t\t}\n\t\t} else {\n\t\t\tsigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)\n\t\t\tif err != nil {\n\t\t\t\tc.sendAlert(alertIllegalParameter)\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tsigned := hs.finishedHash.hashForClientCertificate(sigType)\n\t\t\tif err := verifyLegacyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {\n\t\t\t\tc.sendAlert(alertDecryptError)\n\t\t\t\treturn errors.New(\"tls: invalid signature by the client certificate: \" + err.Error())\n\t\t\t}\n\t\t}\n\n\t\tc.peerSigAlg = certVerify.signatureAlgorithm\n\n\t\tif err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {\n\t\t\treturn err","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_server.go#L779-L815","documentation":"TLS 1.2 path: the server failed to verify the client's CertificateVerify signature using verifyHandshakeSignature. The client's signature over the handshake transcript does not match its certificate's public key, indicating a bad signature, wrong key, or tampered transcript.","triggerScenarios":"verifyHandshakeSignature(sigType, pub, sigHash, hs.finishedHash.buffer, certVerify.signature) returns an error — e.g. crypto/rsa verification failure, ECDSA signature invalid, or Ed25519 mismatch. Triggered when the client signs the wrong data, uses the wrong key, or the transcript diverged.","commonSituations":"A client signing with a different key than the one in its certificate, a transcript hash mismatch caused by a MITM altering handshake messages, a buggy signer, or corruption in transit. Also a possible attack indicator (signature forgery attempt).","solutions":["Verify the client is signing the exact handshake transcript hash with the private key matching its certificate's public key.","Inspect the wrapped err (concatenated into the message) to distinguish rsa.VerifyErr from ecdsa errors.","Check for middleboxes or proxies that alter handshake bytes — they invalidate the transcript.","Ensure the client certificate chain is correctly generated and the key pair matches."],"exampleFix":"// Client must sign the handshake transcript with the matching private key.\n// Go's tls.Config.Certificates / GetClientCertificate handle this automatically.\n// If implementing manual signing, sign hs.finishedHash.buffer exactly as the\n// server will recompute it — do not modify any handshake messages.","handlingStrategy":"try-catch","validationCode":"// Client: verify the cert/key pair match before connecting.\nif err := cert.Leaf.CheckSignatureFrom(cert.Leaf); err == nil {\n    // sanity: cert parses. For key match, compare public key types.\n}\n// More directly: sign a probe transcript and verify with the cert's public key.","typeGuard":null,"tryCatchPattern":"// Server: surface as an mTLS auth failure.\nif err != nil && strings.Contains(err.Error(), \"invalid signature by the client certificate\") {\n    return fmt.Errorf(\"client signature verification failed: %w\", err)\n}","preventionTips":["Ensure client cert and private key are generated as a pair.","Do not alter handshake bytes via proxies or middleboxes.","Test mTLS flows against a known-good peer before deployment."],"tags":["tls","server-handshake","client-certificate","signature-verification","tls12"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}