golang/go · error

tls: missing signature_algorithms from TLS 1.2 peer

Error message

tls: missing signature_algorithms from TLS 1.2 peer

What it means

Thrown when selecting a signature algorithm for a TLS 1.2 client that sent no signature_algorithms extension, and the tlssha1 GODEBUG is not '1'. Per RFC 9155 signature_algorithms is mandatory in TLS 1.2; Go only falls back to the old SHA-1 assumption if GODEBUG tlssha1=1 is set. Otherwise the handshake is rejected.

Source

Thrown at src/crypto/tls/auth.go:286

		supportedAlgs = slices.DeleteFunc(supportedAlgs, func(sigAlg SignatureScheme) bool {
			return !isSupportedSignatureAlgorithm(sigAlg, c.SupportedSignatureAlgorithms)
		})
	}
	// Filter out any unsupported signature algorithms, for example due to
	// FIPS 140-3 policy, tlssha1=0, or protocol version.
	supportedAlgs = slices.DeleteFunc(supportedAlgs, func(sigAlg SignatureScheme) bool {
		return isDisabledSignatureAlgorithm(vers, sigAlg, false)
	})
	if len(supportedAlgs) == 0 {
		return 0, unsupportedCertificateError(c)
	}
	if len(peerAlgs) == 0 && vers == VersionTLS12 {
		// For TLS 1.2, if the client didn't send signature_algorithms then we
		// can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
		// RFC 9155 made signature_algorithms mandatory in TLS 1.2, and we gated
		// it behind the tlssha1 GODEBUG setting.
		if tlssha1.Value() != "1" {
			return 0, errors.New("tls: missing signature_algorithms from TLS 1.2 peer")
		}
		peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1}
	}
	// Pick signature scheme in the peer's preference order, as our
	// preference order is not configurable.
	for _, preferredAlg := range peerAlgs {
		if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
			return preferredAlg, nil
		}
	}
	return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms")
}

// unsupportedCertificateError returns a helpful error for certificates with
// an unsupported private key.
func unsupportedCertificateError(cert *Certificate) error {
	switch cert.PrivateKey.(type) {
	case rsa.PrivateKey, ecdsa.PrivateKey:

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Update the client to send the signature_algorithms extension (RFC 5246/9155).
  2. If you must support the legacy client, set GODEBUG=tlssha1=1 in the environment (re-enables SHA-1 fallback).
  3. Move the connection to TLS 1.3 where signature_algorithms is always present.
  4. Document the SHA-1 security trade-off before enabling tlssha1.

Example fix

// before: client omits signature_algorithms, server rejects
// run with: GODEBUG unset

// after (accept legacy SHA-1 client):
//   GODEBUG=tlssha1=1 ./server
// or prefer: fix the client to send signature_algorithms
Defensive patterns

Strategy: validation

Validate before calling

// Detect a client that omits signature_algorithms before relying on SHA-1 fallback.
func needsSHA1Fallback(chi *tls.ClientHelloInfo) bool {
    return chi != nil && len(chi.SignatureSchemes) == 0
}
// If true and you must serve it, ensure GODEBUG=tlssha1=1 is set or reject.

Try / catch

if err := srv.ListenAndServeTLS("", ""); err != nil {
    if strings.Contains(err.Error(), "missing signature_algorithms from TLS 1.2 peer") {
        log.Printf("set GODEBUG=tlssha1=1 or upgrade the client to send signature_algorithms")
    }
}

Prevention

When it happens

Trigger: Acting as a TLS 1.2 server, the ClientHello omits signature_algorithms and GODEBUG=tlssha1 is unset (default in current Go). selectSignatureScheme returns this error before signing the handshake.

Common situations: A very old or non-conformant client (embedded device, legacy library) that omits signature_algorithms; Go upgraded to a version that gated SHA-1 fallback behind tlssha1; server pinned to TLS 1.2 with such clients.

Understand the failure class

Related errors


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