golang/go · error

tls: no supported elliptic curves offered

Error message

tls: no supported elliptic curves offered

What it means

During TLS 1.0–1.2 ECDHE key exchange, the server iterates the client's supportedCurves list looking for one that the server also supports (via config.supportsCurve). If no overlap is found (ka.curveID remains 0), the server cannot proceed with ECDHE key exchange. The client must offer at least one curve the server supports.

Source

Thrown at src/crypto/tls/key_agreement.go:167

	preMasterSecret []byte

	// curveID, signatureAlgorithm, and key are set by processServerKeyExchange
	// and generateServerKeyExchange.
	curveID            CurveID
	signatureAlgorithm SignatureScheme
	key                *ecdh.PrivateKey
}

func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
	for _, c := range clientHello.supportedCurves {
		if config.supportsCurve(ka.version, c) {
			ka.curveID = c
			break
		}
	}

	if ka.curveID == 0 {
		return nil, errors.New("tls: no supported elliptic curves offered")
	}
	if _, ok := curveForCurveID(ka.curveID); !ok {
		return nil, errors.New("tls: internal error: supportsCurve accepted unimplemented curve")
	}

	key, err := generateECDHEKey(config.rand(), ka.curveID)
	if err != nil {
		return nil, err
	}
	ka.key = key

	// See RFC 4492, Section 5.4.
	ecdhePublic := key.PublicKey().Bytes()
	serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
	serverECDHEParams[0] = 3 // named curve
	serverECDHEParams[1] = byte(ka.curveID >> 8)
	serverECDHEParams[2] = byte(ka.curveID)
	serverECDHEParams[3] = byte(len(ecdhePublic))

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Ensure the client offers at least one standard curve the server supports (X25519, P-256, P-384 are universally recommended).
  2. On the server, verify tls.Config.CurvePreferences includes common curves (or leave it nil for defaults).
  3. Update the client TLS library to one that advertises standard curves.
  4. If running in FIPS mode, ensure the client offers NIST curves (P-256, P-384) since X25519 may not be available.
  5. Prefer TLS 1.3 which has better curve negotiation and defaults.

Example fix

// before: client offers no supported curves (or server restricts too much)
cfg := &tls.Config{
    CurvePreferences: []tls.CurveID{}, // empty - too restrictive
}
// after: include standard curves
cfg := &tls.Config{
    CurvePreferences: []tls.CurveID{
        tls.X25519, tls.CurveP256, tls.CurveP384,
    },
}
Defensive patterns

Strategy: validation

Validate before calling

// Server-side: verify curve configuration before accepting connections
func validateCurveConfig(cfg *tls.Config) error {
    if len(cfg.CurvePreferences) == 0 {
        return nil // defaults are fine
    }
    standardCurves := map[tls.CurveID]bool{
        tls.X25519: true, tls.CurveP256: true, tls.CurveP384: true, tls.CurveP521: true,
    }
    for _, c := range cfg.CurvePreferences {
        if !standardCurves[c] {
            return fmt.Errorf("non-standard curve %v in preferences", c)
        }
    }
    return nil
}

Try / catch

// Server-side: log and close
if err := conn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "no supported elliptic curves") {
        log.Printf("client offered no supported curves: %v", err)
    }
    conn.Close()
}

Prevention

When it happens

Trigger: Server calls ecdheKeyAgreement.generateServerKeyExchange. The clientHello.supportedCurves list is empty, or contains only curves the server doesn't support (e.g. client offers only custom/obsolete curves the server's config rejects).

Common situations: Client offers only non-standard or deprecated curves; server's CurvePreferences list is too restrictive; client configured with an empty or exotic supported curves list; version mismatch where a client only supports curves the server dropped; FIPS-mode server that restricts curve selection.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/9b6b50ccdc85b01a. Report an issue: GitHub.