{"record":{"id":"dfacab79b7a6d620","repo":"golang/go","slug":"tls-failed-to-sign-handshake-err","errorCode":null,"errorMessage":"tls: failed to sign handshake: {err}","messagePattern":"tls: failed to sign handshake: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_client_tls13.go","lineNumber":802,"sourceCode":"\t\t// CertificateRequestInfo supported signature algorithms.\n\t\tc.sendAlert(alertHandshakeFailure)\n\t\treturn err\n\t}\n\n\tsigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)\n\tif err != nil {\n\t\treturn c.sendAlert(alertInternalError)\n\t}\n\n\tsigned := signedMessage(clientSignatureContext, hs.transcript)\n\tsignOpts := crypto.SignerOpts(sigHash)\n\tif sigType == signatureRSAPSS {\n\t\tsignOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}\n\t}\n\tsig, err := crypto.SignMessage(cert.PrivateKey.(crypto.Signer), c.config.rand(), signed, signOpts)\n\tif err != nil {\n\t\tc.sendAlert(alertInternalError)\n\t\treturn errors.New(\"tls: failed to sign handshake: \" + err.Error())\n\t}\n\tcertVerifyMsg.signature = sig\n\n\tif _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (hs *clientHandshakeStateTLS13) sendClientFinished() error {\n\tc := hs.c\n\n\tfinished := &finishedMsg{\n\t\tverifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),\n\t}\n\n\tif _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {","sourceCodeStart":784,"sourceCodeEnd":820,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client_tls13.go#L784-L820","documentation":"Thrown during the TLS 1.3 client handshake when signing the CertificateVerify message fails. The client calls crypto.SignMessage with its private key (RSA-PSS, ECDSA, or Ed25519) over the transcript hash, and the underlying signer returned an error. This is a local signing failure, not a network or peer problem.","triggerScenarios":"clientHandshakeStateTLS13.sendClientCertificateVerify invokes crypto.Signer.Sign via crypto.SignMessage with cert.PrivateKey; failure occurs when the PrivateKey does not implement crypto.Signer, the key is corrupt/unreadable, an HSM/PKCS#11 backing the key rejects the operation, or RSA-PSS salt length / hash parameters are incompatible with the key.","commonSituations":"Loading a certificate with a private key that omits Sign (e.g. a raw *rsa.PrivateKey wrapped incorrectly), a hardware token yanked mid-handshake, an HSM policy blocking the requested hash, or feeding a key parsed without the matching Parse function so its internal state is incomplete.","solutions":["Verify the configured tls.Certificate.PrivateKey implements crypto.Signer (all standard *rsa.PrivateKey, *ecdsa.PrivateKey, and ed25519.PrivateKey values do).","Ensure the private key was loaded with the correct parser (x509.ParsePKCS1PrivateKey / ParsePKCS8PrivateKey / ParseECPrivateKey) and matches the certificate's public key algorithm.","If the key lives in an HSM or PKCS#11 module, check that the token is present, the session is authorized, and the mechanism (RSA-PSS with PSSSaltLengthEqualsHash) is permitted by token policy.","Log the wrapped err (err.Error() is concatenated into the message) to identify whether it is a crypto/rsa, crypto/ecdsa, or signer-type error."],"exampleFix":"// before\ncert, err := tls.LoadX509KeyPair(\"client.crt\", \"client.key\")\nif err != nil { return err }\n// client.key was an encrypted PEM; PrivateKey came back nil/invalid\n\n// after\ndecryptPEM, err := decryptBlock(pemBlock, password)\ncert, err := tls.X509KeyPair(certPEM, decryptPEM)\nif err != nil { return err }\nif _, ok := cert.PrivateKey.(crypto.Signer); !ok {\n    return errors.New(\"private key does not implement crypto.Signer\")\n}","handlingStrategy":"try-catch","validationCode":"// Before dialing, ensure the client cert key can sign.\nif cert, ok := tlsCert.PrivateKey.(crypto.Signer); ok {\n    // Optionally dry-run a signature over random bytes with the same\n    // opts you expect TLS to use.\n    h := sha256.Sum256([]byte(\"probe\"))\n    if _, err := cert.Sign(rand.Reader, h[:], crypto.SHA256); err != nil {\n        return fmt.Errorf(\"private key unusable: %w\", err)\n    }\n} else {\n    return errors.New(\"private key does not implement crypto.Signer\")\n}","typeGuard":"func isCryptoSigner(k any) bool {\n    _, ok := k.(crypto.Signer)\n    return ok\n}","tryCatchPattern":"// Wrap tls.Dial / http.Client.Do and inspect the error string.\nconn, err := tls.Dial(\"tcp\", addr, cfg)\nif err != nil && strings.Contains(err.Error(), \"failed to sign handshake\") {\n    // surface as a credential/key problem, not a network error\n    return fmt.Errorf(\"client key signing failed: %w\", err)\n}","preventionTips":["Always load key pairs with tls.X509KeyPair / LoadX509KeyPair and check the returned error.","For HSM-backed keys, run a preflight Sign probe during startup, not at first request.","Assert cert.PrivateKey.(crypto.Signer) at config time, not handshake time."],"tags":["tls","crypto","client-handshake","signing","tls13"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}