golang/go · error · CertificateVerificationError

client's certificate is not allowed in FIPS 140-3 mode

Error message

client's certificate is not allowed in FIPS 140-3 mode

What it means

FIPS 140-3 mode is enabled and the client's leaf certificate uses an algorithm or curve that is not on the FIPS-approved list (isCertificateAllowedFIPS returned false). FIPS-compliant deployments must reject non-approved client certificates; the server alerts bad_certificate and wraps the error in a CertificateVerificationError.

Source

Thrown at src/crypto/tls/handshake_server.go:1008

			}
			return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
		}

		c.verifiedChains, err = fipsAllowedChains(chains)
		if err != nil {
			c.sendAlert(alertBadCertificate)
			return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
		}
	}

	c.peerCertificates = certs
	c.ocspResponse = certificate.OCSPStaple
	c.scts = certificate.SignedCertificateTimestamps

	if len(certs) > 0 {
		if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) {
			c.sendAlert(alertBadCertificate)
			err := errors.New("client's certificate is not allowed in FIPS 140-3 mode")
			return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
		}

		switch certs[0].PublicKey.(type) {
		case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
		case *mldsa.PublicKey:
			if c.vers < VersionTLS13 {
				c.sendAlert(alertIllegalParameter)
				return errors.New("tls: client certificate uses ML-DSA, which requires TLS 1.3")
			}
		default:
			c.sendAlert(alertUnsupportedCertificate)
			return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
		}
	}

	if c.config.VerifyPeerCertificate != nil {
		if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Reissue the client certificate using FIPS-approved parameters (RSA >= 2048, P-256/P-384 curves, SHA-256+ signatures).
  2. Verify against the FIPS 140-3 allowed algorithm list for your Go toolchain version.
  3. If FIPS enforcement is not actually required, recompile without the FIPS toolchain — but this changes your compliance posture.
  4. Track which clients present non-compliant certs and migrate them first.

Example fix

// Reissue client cert with FIPS-approved parameters
// Key: ECDSA P-256 (or RSA 2048+)
// Signature: SHA256withECDSA (or SHA256withRSA)

// openssl example:
// openssl ecparam -name prime256v1 -genkey -noout -out client.key
// openssl req -new -x509 -key client.key -out client.crt -sha256
Defensive patterns

Strategy: validation

Validate before calling

// Validate client cert against FIPS-allowed algorithms before relying on it.
// (On the server side this happens automatically; on the issuing side, use
// FIPS-approved parameters at generation time.)
func isFIPSApprovedCert(c *x509.Certificate) bool {
    switch k := c.PublicKey.(type) {
    case *rsa.PublicKey:
        return k.N.BitLen() >= 2048
    case *ecdsa.PublicKey:
        return k.Curve == elliptic.P256() || k.Curve == elliptic.P384()
    }
    return false // adjust per your Go toolchain's FIPS list
}

Try / catch

// Server in FIPS mode: catch and reject with a clear message.
if err != nil && strings.Contains(err.Error(), "not allowed in FIPS 140-3 mode") {
    return fmt.Errorf("client cert non-FIPS-compliant: %w", err)
}

Prevention

When it happens

Trigger: processCertsFromClient: fips140tls.Required() is true and isCertificateAllowedFIPS(certs[0]) is false. The client cert uses e.g. an unapproved curve (P-224, ed25519 in some configs), an RSA key < 2048 bits, or a non-FIPS signature algorithm.

Common situations: FIPS-mode server facing a client presenting an EC certificate on a non-approved curve, a small RSA key, or a post-quantum/mixed algorithm not yet FIPS-validated. Common during FIPS migration when not all clients have been upgraded.

Understand the failure class

Related errors


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