{"record":{"id":"001c02836b8c6ed2","repo":"golang/go","slug":"tls-certificate-private-key-does-not-implement-cr","errorCode":null,"errorMessage":"tls: certificate private key does not implement crypto.Decrypter","messagePattern":"tls: certificate private key does not implement crypto\\.Decrypter","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/tls/key_agreement.go","lineNumber":62,"sourceCode":"type rsaKeyAgreement struct{}\n\nfunc (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {\n\treturn nil, nil\n}\n\nfunc (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {\n\tif len(ckx.ciphertext) < 2 {\n\t\treturn nil, errClientKeyExchange\n\t}\n\tciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])\n\tif ciphertextLen != len(ckx.ciphertext)-2 {\n\t\treturn nil, errClientKeyExchange\n\t}\n\tciphertext := ckx.ciphertext[2:]\n\n\tpriv, ok := cert.PrivateKey.(crypto.Decrypter)\n\tif !ok {\n\t\treturn nil, errors.New(\"tls: certificate private key does not implement crypto.Decrypter\")\n\t}\n\t// Perform constant time RSA PKCS #1 v1.5 decryption\n\tpreMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// We don't check the version number in the premaster secret. For one,\n\t// by checking it, we would leak information about the validity of the\n\t// encrypted pre-master secret. Secondly, it provides only a small\n\t// benefit against a downgrade attack and some implementations send the\n\t// wrong version anyway. See the discussion at the end of section\n\t// 7.4.7.1 of RFC 4346.\n\treturn preMasterSecret, nil\n}\n\nfunc (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {\n\treturn errors.New(\"tls: unexpected ServerKeyExchange\")\n}","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/key_agreement.go#L44-L80","documentation":"During TLS 1.0–1.2 RSA key exchange, the server's certificate private key does not implement the crypto.Decrypter interface. The RSA key agreement requires decrypting the client's encrypted pre-master secret using priv.Decrypt(). If the private key type (even though it's an RSA key) doesn't implement crypto.Decrypter, decryption cannot proceed. Standard *rsa.PrivateKey implements crypto.Decrypter, so this error implies a custom key type.","triggerScenarios":"Server calls rsaKeyAgreement.processClientKeyExchange and attempts cert.PrivateKey.(crypto.Decrypter). The type assertion fails because the private key is a custom type that wraps an RSA key but doesn't expose the Decrypt method, or the key is stored in a way (e.g. some HSM integrations) that only implements crypto.Signer but not crypto.Decrypter.","commonSituations":"Custom private key type (e.g. PKCS#11 wrapper, cloud KMS proxy) that implements crypto.Signer but not crypto.Decrypter; an HSM-backed key that only supports signing; a key loaded from an unusual source that doesn't fully implement the standard interfaces.","solutions":["Use a standard *rsa.PrivateKey loaded via tls.LoadX509KeyPair or x509.ParsePKCS1PrivateKey.","If using a custom key type, implement crypto.Decrypter (Decrypt method) on it.","For HSM keys: ensure the HSM/PKCS#11 provider supports RSA decryption and exposes it via crypto.Decrypter.","Switch to an ECDHE cipher suite that only requires signing (crypto.Signer), not decryption.","Provide the key via a tls.Certificate where PrivateKey fully implements crypto.Decrypter."],"exampleFix":"// before: custom key type only implements crypto.Signer\ncert := tls.Certificate{\n    PrivateKey: myCustomSignerOnlyKey,\n}\n// after: implement crypto.Decrypter or use standard key\ncert := tls.Certificate{\n    PrivateKey: parsedRSAKey, // *rsa.PrivateKey implements crypto.Decrypter\n}\n// Or implement Decrypt on your custom type:\n// func (k *CustomKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) ([]byte, error) { ... }","handlingStrategy":"type-guard","validationCode":"// Verify the private key implements crypto.Decrypter before starting the server\nfunc verifyDecrypter(cert *tls.Certificate) error {\n    _, ok := cert.PrivateKey.(crypto.Decrypter)\n    if !ok {\n        return errors.New(\"private key must implement crypto.Decrypter for RSA key exchange\")\n    }\n    return nil\n}","typeGuard":"func isDecrypter(key any) bool {\n    _, ok := key.(crypto.Decrypter)\n    return ok\n}","tryCatchPattern":"// Check at server startup\nif err := verifyDecrypter(&cert); err != nil {\n    log.Fatal(\"certificate key not suitable for RSA key exchange: \", err)\n}\n// Or handle at handshake time:\nif err := conn.Handshake(); err != nil {\n    if strings.Contains(err.Error(), \"crypto.Decrypter\") {\n        log.Printf(\"key type issue: %v\", err)\n    }\n}","preventionTips":["Use standard *rsa.PrivateKey from tls.LoadX509KeyPair for RSA cipher suites.","If using custom key types, implement crypto.Decrypter.","Prefer ECDHE cipher suites that only require crypto.Signer.","Verify key capabilities at startup, not at handshake time."],"tags":["tls","tls12","rsa","key-exchange","crypto-decrypter","certificate","server-side"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}