golang/go · critical
tls: server certificate contains incorrect key type for sele
Error message
tls: server certificate contains incorrect key type for selected ciphersuite
What it means
During TLS 1.0–1.2 RSA key exchange on the client side, the server's certificate public key is not an *rsa.PublicKey. The RSA key agreement requires encrypting the pre-master secret to the server's RSA public key via rsa.EncryptPKCS1v15. If the cert contains an ECDSA, Ed25519, or other non-RSA key, this type assertion fails.
Source
Thrown at src/crypto/tls/key_agreement.go:93
return preMasterSecret, nil
}
func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
return errors.New("tls: unexpected ServerKeyExchange")
}
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
preMasterSecret := make([]byte, 48)
preMasterSecret[0] = byte(clientHello.vers >> 8)
preMasterSecret[1] = byte(clientHello.vers)
_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
if err != nil {
return nil, nil, err
}
rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
if !ok {
return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
}
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
if err != nil {
return nil, nil, err
}
ckx := new(clientKeyExchangeMsg)
ckx.ciphertext = make([]byte, len(encrypted)+2)
ckx.ciphertext[0] = byte(len(encrypted) >> 8)
ckx.ciphertext[1] = byte(len(encrypted))
copy(ckx.ciphertext[2:], encrypted)
return preMasterSecret, ckx, nil
}
// sha1Hash calculates a SHA1 hash over the given byte slices.
func sha1Hash(slices [][]byte) []byte {
hsha1 := sha1.New()
for _, slice := range slices {
hsha1.Write(slice)View on GitHub (pinned to b6b368adc5)
Solutions
- Ensure the server certificate key type matches the negotiated cipher suite (RSA cert for RSA suites, ECDSA cert for ECDSA suites).
- Configure the client to prefer ECDHE cipher suites that match the server's certificate key type.
- Verify the server is loading the correct certificate for the connection.
- Use tls.Config.Certificates to provide both RSA and ECDSA certs so the server can select the right one.
- Update to TLS 1.3 which decouples key exchange from authentication, avoiding this class of mismatch.
Example fix
// before: server has only ECDSA cert but client negotiates RSA cipher suite
cfg := &tls.Config{
CipherSuites: []uint16{tls.TLS_RSA_WITH_AES_128_CBC_SHA}, // requires RSA cert
Certificates: []tls.Certificate{ecdsaCert}, // wrong key type!
}
// after: provide matching RSA cert or use ECDHE suites
cfg := &tls.Config{
CipherSuites: []uint16{tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
Certificates: []tls.Certificate{ecdsaCert}, // now matches
} Defensive patterns
Strategy: type-guard
Validate before calling
// Verify server cert key type before connecting (if cert is known)
func verifyRSACertKeyType(cert *x509.Certificate) error {
if _, ok := cert.PublicKey.(*rsa.PublicKey); !ok {
return errors.New("server certificate is not RSA but RSA key exchange was negotiated")
}
return nil
} Type guard
func isRSAPublicKey(pub any) bool {
_, ok := pub.(*rsa.PublicKey)
return ok
} Try / catch
// Client-side: handle during handshake
if err := conn.Handshake(); err != nil {
if strings.Contains(err.Error(), "incorrect key type") {
log.Printf("server cert key type mismatch: %v", err)
}
} Prevention
- Prefer ECDHE cipher suites that match the server's cert key type.
- Don't force RSA key exchange suites unless you know the server has an RSA cert.
- Use TLS 1.3 to avoid cert-key-type/cipher-suite coupling.
- Configure client CipherSuites to include both RSA and ECDSA ECDHE variants.
When it happens
Trigger: Client calls rsaKeyAgreement.generateClientKeyExchange and attempts cert.PublicKey.(*rsa.PublicKey). The negotiated cipher suite is an RSA key-exchange suite (e.g. TLS_RSA_WITH_AES_128_CBC_SHA), but the server's certificate uses a non-RSA key (e.g. ECDSA P-256).
Common situations: Cipher suite and certificate key type mismatch: server presents an ECDSA cert but the client/server negotiated an RSA key exchange cipher suite; misconfigured server that loads the wrong certificate for the negotiated cipher suite; client forces RSA suites while server only has ECDSA certs (or vice versa).
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: certificate private key does not implement crypto.Decry
- tls: unexpected ServerKeyExchange
- tls: no supported elliptic curves offered
- tls: certificate cannot be used with the selected cipher sui
- tls: server selected unsupported curve
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/55ea8e7a27964bbc.
Report an issue: GitHub.