golang/go · error

tls: certificate used with invalid signature algorithm

Error message

tls: certificate used with invalid signature algorithm

What it means

readServerCertificateVerify rejects a CertificateVerify message whose signature algorithm is not in the client's supported set for TLS 1.3 AND not valid for the certificate's public key type. RFC 8446 §4.2.3 constrains the algorithm; Go sends `illegal_parameter` on mismatch. Indicates a server signing with an algorithm the client did not offer or that does not match the cert key.

Source

Thrown at src/crypto/tls/handshake_client_tls13.go:660

	// this message was sent is used.
	msg, err = c.readHandshake(nil)
	if err != nil {
		return err
	}

	certVerify, ok := msg.(*certificateVerifyMsg)
	if !ok {
		c.sendAlert(alertUnexpectedMessage)
		return unexpectedMessageError(certVerify, msg)
	}

	// See RFC 8446, Section 4.4.3.
	// We don't use hs.hello.supportedSignatureAlgorithms because it might
	// include PKCS#1 v1.5 and SHA-1 if the ClientHello also supported TLS 1.2.
	if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms(c.vers, c.vers)) ||
		!isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, signatureSchemesForPublicKey(c.vers, c.peerCertificates[0].PublicKey)) {
		c.sendAlert(alertIllegalParameter)
		return errors.New("tls: certificate used with invalid signature algorithm")
	}
	sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
	if err != nil {
		return c.sendAlert(alertInternalError)
	}
	if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
		return c.sendAlert(alertInternalError)
	}
	signed := signedMessage(serverSignatureContext, hs.transcript)
	if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
		sigHash, signed, certVerify.signature); err != nil {
		c.sendAlert(alertDecryptError)
		return errors.New("tls: invalid signature by the server certificate: " + err.Error())
	}
	c.peerSigAlg = certVerify.signatureAlgorithm

	if err := transcriptMsg(certVerify, hs.transcript); err != nil {
		return err

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Update the server certificate and signing logic to use TLS 1.3-approved algorithms (ECDSA-with-SHA256/384/512, RSASSA-PSS, Ed25519).
  2. Confirm the leaf certificate key type matches the signature algorithm the server emits.
  3. If you cannot change the server, restrict MaxVersion to tls.VersionTLS12 to fall back to TLS 1.2 rules.
  4. Capture the CertificateVerify and confirm the algorithm code against RFC 8446 §4.2.3.

Example fix

// before: client defaults to TLS 1.3, which rejects the server's legacy sig alg
cfg := &tls.Config{}

// after: cap at TLS 1.2 if the server cannot be upgraded (temporary workaround)
cfg := &tls.Config{MaxVersion: tls.VersionTLS12}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: if you know the server is TLS 1.2-era, cap MaxVersion so TLS 1.3 sig rules do not apply.
if serverLegacySignatures {
    cfg.MaxVersion = tls.VersionTLS12
}

Try / catch

if err := conn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "invalid signature algorithm") {
        // server is using a TLS-1.3-forbidden algorithm; upgrade server or cap at TLS 1.2
        cfg.MaxVersion = tls.VersionTLS12
        return retryHandshake(addr, cfg)
    }
}

Prevention

When it happens

Trigger: certVerify.signatureAlgorithm is not in supportedSignatureAlgorithms(c.vers, c.vers) OR not in signatureSchemesForPublicKey of the leaf cert. Reached during CertificateVerify processing.

Common situations: Server using an older signature algorithm (e.g., PKCS#1 v1.5, SHA-1) that TLS 1.3 forbids, a cert/key-type mismatch on the server (e.g., DSA cert), or a server that ignores the client's signature_algorithms extension. Browser/standard clients reject these too.

Understand the failure class

Related errors


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