{"record":{"id":"83e4a4675930405e","repo":"golang/go","slug":"tls-certificate-cannot-be-used-with-the-selected","errorCode":null,"errorMessage":"tls: certificate cannot be used with the selected cipher suite","messagePattern":"tls: certificate cannot be used with the selected cipher suite","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/tls/key_agreement.go","lineNumber":209,"sourceCode":"\t}\n\n\tvar sig []byte\n\tif ka.version >= VersionTLS12 {\n\t\tka.signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsigType, sigHash, err := typeAndHashFromSignatureScheme(ka.signatureAlgorithm)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif sigHash == crypto.SHA1 {\n\t\t\ttlssha1.Value() // ensure godebug is initialized\n\t\t\ttlssha1.IncNonDefault()\n\t\t}\n\t\tsigned := slices.Concat(clientHello.random, hello.random, serverECDHEParams)\n\t\tif (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {\n\t\t\treturn nil, errors.New(\"tls: certificate cannot be used with the selected cipher suite\")\n\t\t}\n\t\tsignOpts := crypto.SignerOpts(sigHash)\n\t\tif sigType == signatureRSAPSS {\n\t\t\tsignOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}\n\t\t}\n\t\tsig, err = crypto.SignMessage(priv, config.rand(), signed, signOpts)\n\t\tif err != nil {\n\t\t\treturn nil, errors.New(\"tls: failed to sign ECDHE parameters: \" + err.Error())\n\t\t}\n\t} else {\n\t\tsigType, sigHash, err := legacyTypeAndHashFromPublicKey(priv.Public())\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsigned := hashForServerKeyExchange(sigType, clientHello.random, hello.random, serverECDHEParams)\n\t\tif (sigType == signaturePKCS1v15) != ka.isRSA {\n\t\t\treturn nil, errors.New(\"tls: certificate cannot be used with the selected cipher suite\")\n\t\t}","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/key_agreement.go#L191-L227","documentation":"During TLS 1.0–1.2 ECDHE ServerKeyExchange signing (modern signing path using crypto.SignMessage), the server's certificate key type doesn't match what the cipher suite expects. The check (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA fires when an RSA cipher suite is paired with an ECDSA cert, or an ECDSA cipher suite is paired with an RSA cert. The ka.isRSA flag was set during cipher suite selection.","triggerScenarios":"Server signs ECDHE parameters using ka.signatureAlgorithm. If the negotiated cipher suite is ECDHE-RSA (ka.isRSA=true) but the certificate is ECDSA, or the suite is ECDHE-ECDSA (ka.isRSA=false) but the cert is RSA, this mismatch triggers.","commonSituations":"Server loaded the wrong certificate type for the negotiated cipher suite; misconfigured tls.Config.Certificates with multiple certs where the wrong one was selected; cipher suite preferences and certificate availability are out of sync; a server update changed cert type without updating cipher suite config.","solutions":["Ensure the certificate key type matches the cipher suite family: RSA certs for ECDHE-RSA suites, ECDSA certs for ECDHE-ECDSA suites.","Provide both RSA and ECDSA certificates in tls.Config.Certificates so Go can auto-select the right one.","Verify tls.Config.CipherSuites only includes suites compatible with the loaded certificate(s).","Use GetCertificate callback to dynamically select the correct cert based on the negotiated cipher suite.","Prefer TLS 1.3 which decouples authentication key type from key exchange."],"exampleFix":"// before: ECDSA cert with RSA-only cipher suites\ncfg := &tls.Config{\n    Certificates: []tls.Certificate{ecdsaCert},\n    CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, // needs RSA!\n}\n// after: match cipher suites to cert or provide both\ncfg := &tls.Config{\n    Certificates: []tls.Certificate{ecdsaCert},\n    CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},\n}","handlingStrategy":"type-guard","validationCode":"// Verify cert/cipher-suite compatibility before starting the server\nfunc validateCertCipherSuiteCompat(cert *tls.Certificate, cipherSuites []uint16) error {\n    isRSA := false\n    switch cert.PrivateKey.(crypto.Signer).Public().(type) {\n    case *rsa.PublicKey:\n        isRSA = true\n    }\n    for _, suite := range cipherSuites {\n        suiteIsRSA := strings.Contains(cipherSuiteName(suite), \"_RSA_\") ||\n                      (!strings.Contains(cipherSuiteName(suite), \"_ECDSA_\"))\n        // Simplified check — adapt to actual suite classification\n        if isRSA != suiteIsRSA && strings.Contains(cipherSuiteName(suite), \"ECDHE\") {\n            // Potential mismatch for ECDHE suites\n        }\n    }\n    return nil\n}","typeGuard":"// Determine if certificate key is RSA for cipher suite matching\nfunc isRSACert(cert *tls.Certificate) bool {\n    signer, ok := cert.PrivateKey.(crypto.Signer)\n    if !ok {\n        return false\n    }\n    _, isRSA := signer.Public().(*rsa.PublicKey)\n    return isRSA\n}","tryCatchPattern":"// Validate at startup\nfor _, suite := range cfg.CipherSuites {\n    if err := validateCertCipherSuiteCompat(&cert, cfg.CipherSuites); err != nil {\n        log.Fatal(\"cert/cipher-suite mismatch: \", err)\n    }\n}\n// Runtime:\nif err := conn.Handshake(); err != nil {\n    if strings.Contains(err.Error(), \"certificate cannot be used\") {\n        log.Printf(\"cert/suite mismatch: %v\", err)\n    }\n}","preventionTips":["Provide both RSA and ECDSA certificates in tls.Config.Certificates.","Ensure CipherSuites list is compatible with loaded certificates.","Validate cert/cipher-suite compatibility at startup.","Use GetCertificate callback for dynamic cert selection.","Prefer TLS 1.3 to avoid cert-key-type coupling."],"tags":["tls","tls12","ecdhe","certificate","cipher-suite","signing","server-side"],"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}