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
When the FIPS 140-3 module is required (fips140tls.Required() returns true), the server declining Extended Master Secret (RFC 7627) on a TLS 1.2 handshake is a hard violation unless the GODEBUG switch fips140ems is explicitly set to "0". Without EMS the master secret uses the legacy derivation, which FIPS 140-3 disallows.
Source
Thrown at src/crypto/tls/handshake_client.go:778
if err != nil {
c.sendAlert(alertInternalError)
return err
}
if ckx != nil {
if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
return err
}
}
if hs.serverHello.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.hello.random, hs.serverHello.random)
}
if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
c.sendAlert(alertInternalError)
return errors.New("tls: failed to write to key log: " + err.Error())
}
if chainToSend != nil && len(chainToSend.Certificate) > 0 {
certVerify := &certificateVerifyMsg{}
key, ok := chainToSend.PrivateKey.(crypto.Signer)
if !ok {
c.sendAlert(alertInternalError)
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)View on GitHub (pinned to b6b368adc5)
Solutions
- Upgrade/patch the server to support Extended Master Secret (RFC 7627) — almost all modern servers do.
- If site policy permits the relaxation, set GODEBUG=tlsems=0 (fips140ems=0) — but this breaks FIPS 140-3 compliance of the connection.
- Confirm GODEBUG=fips140=on is actually required for this workload; remove it if not.
- Prefer TLS 1.3, where EMS semantics are mandatory.
Example fix
// Prefer fixing the server. If policy allows relaxation, document the trade-off:
// GODEBUG=tlsems=0 go run ./cmd
// Otherwise move the peer to TLS 1.3.
cfg := &tls.Config{MinVersion: tls.VersionTLS13} Defensive patterns
Strategy: validation
Validate before calling
// Confirm FIPS posture is intentional and that you are not over-restricting. // If the peer lacks EMS, either fix the peer or explicitly opt out (non-FIPS). // GODEBUG=tlsems=0 disables the requirement but breaks FIPS 140-3 compliance.
Type guard
func isFIPSEMSRequired(err error) bool {
return err != nil && strings.Contains(err.Error(), "FIPS 140-3 requires the use of Extended Master Secret")
} Try / catch
if _, err := tls.Dial("tcp", addr, cfg); err != nil {
if isFIPSEMSRequired(err) {
// Do not silently relax: decide whether FIPS is truly required here.
log.Printf("compliance: peer %s lacks EMS; refusing under FIPS policy", addr)
}
} Prevention
- Confirm GODEBUG=fips140=on is required before relying on it.
- Ensure peers support RFC 7627 EMS.
- Prefer TLS 1.3 where EMS is mandatory.
When it happens
Trigger: Connecting from a FIPS-required Go build (GOEXPERIMENT=fips140 / GODEBUG=fips140=on) to a TLS 1.2 server whose ServerHello did not include the extended_master_session extension; the else-branch fires.
Common situations: FIPS-compliance-enforced deployments (government, finance, healthcare) talking to legacy or non-compliant servers; misconfigured GODEBUG FIPS settings.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- server's certificate is not allowed in FIPS 140-3 mode
- crypto/des: use of DES is not allowed in FIPS 140-only mode
- crypto/des: use of TripleDES is not allowed in FIPS 140-only
- crypto/dsa: use of DSA is not allowed in FIPS 140-only mode
- crypto/ecdh: only crypto/rand.Reader is allowed in FIPS 140-
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/95c5cd0a59e02e7b.
Report an issue: GitHub.