golang/go · error
tls: FIPS 140-3 requires the use of Extended Master Secret
Error message
tls: FIPS 140-3 requires the use of Extended Master Secret
What it means
FIPS 140-3 mode is enabled and the negotiated TLS 1.2 handshake did not use extended_master_secret. FIPS 140-3 mandates EMS; the server rejects the handshake with handshake_failure when fips140ems is at its non-default (enforcing) value.
Source
Thrown at src/crypto/tls/handshake_server.go:744
if !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(ckx, msg)
}
preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
if err != nil {
c.sendAlert(alertIllegalParameter)
return err
}
if hs.hello.extendedMasterSecret {
c.extMasterSecret = true
hs.masterSecret = extMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
hs.finishedHash.Sum())
} else {
if fips140tls.Required() {
if fips140ems.Value() != "0" {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: FIPS 140-3 requires the use of Extended Master Secret")
}
fips140ems.IncNonDefault()
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret,
hs.clientHello.random, hs.hello.random)
}
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return err
}
// If we received a client cert in response to our certificate request message,
// the client will send us a certificateVerifyMsg immediately after the
// clientKeyExchangeMsg. This message is a digest of all preceding
// handshake-layer messages that is signed using the private key corresponding
// to the client's certificate. This allows us to verify that the client is in
// possession of the private key of the certificate.
if len(c.peerCertificates) > 0 {View on GitHub (pinned to b6b368adc5)
Solutions
- Require the client to advertise extended_master_secret (RFC 7627) — upgrade legacy clients.
- If the deployment cannot avoid FIPS mode, all peers must support EMS; there is no bypass while keeping compliance.
- To temporarily disable enforcement, set the fips140ems godebug to "0" — but this breaks FIPS compliance and should only be used for diagnostics.
- Document the FIPS requirement in your deployment policy so client integrators know EMS is mandatory.
Example fix
// Client fix: ensure extended_master_secret is advertised. // Go clients always advertise it for TLS 1.2; no action required. // Legacy OpenSSL clients: upgrade to >= 1.1.0 where EMS is default-on. // Diagnostic only (NOT for production — breaks FIPS): // GODEBUG=fips140ems=0
Defensive patterns
Strategy: validation
Validate before calling
// In FIPS mode, gate peer acceptance on EMS advertisement before handshake. // (Detection happens at handshake; ensure all deployed clients support EMS.)
Try / catch
// Server in FIPS mode: catch and reject non-EMS clients.
if err != nil && strings.Contains(err.Error(), "FIPS 140-3 requires the use of Extended Master Secret") {
return fmt.Errorf("client incompatible with FIPS policy: %w", err)
} Prevention
- Document that all clients of a FIPS-mode server must support EMS.
- Run clients on TLS stacks >= OpenSSL 1.1.0 / current Go.
- Avoid setting GODEBUG=fips140ems=0 in production — it breaks compliance.
When it happens
Trigger: In the TLS 1.2 master-secret derivation, hs.hello.extendedMasterSecret is false, fips140tls.Required() is true, and fips140ems.Value() != "0". The client either omitted EMS or stripped it.
Common situations: Operating in a FIPS-validated environment (Go compiled with GOEXPERIMENT=boringcrypto or the FIPS-enabled toolchain) where EMS is mandatory but the peer is a legacy/non-compliant client that does not advertise extended_master_secret.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- client's certificate is not allowed in FIPS 140-3 mode
- tls: FIPS 140-3 requires the use of Extended Master Secret
- server's certificate is not allowed in FIPS 140-3 mode
- tls: client does not support uncompressed connections
- tls: initial handshake had non-empty renegotiation extension
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/069a5b8ce2f9fc22.
Report an issue: GitHub.