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

  1. Require the client to advertise extended_master_secret (RFC 7627) — upgrade legacy clients.
  2. If the deployment cannot avoid FIPS mode, all peers must support EMS; there is no bypass while keeping compliance.
  3. To temporarily disable enforcement, set the fips140ems godebug to "0" — but this breaks FIPS compliance and should only be used for diagnostics.
  4. 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

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

Related errors


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