golang/go · error

tls: client certificate used with invalid signature algorith

Error message

tls: client certificate used with invalid signature algorithm

What it means

During mutual TLS (mTLS) client certificate verification, the client's CertificateVerify message specified a signature algorithm that the server doesn't support. The check uses two filters: (1) the algorithm must be in the server's supportedSignatureAlgorithms list for the negotiated version, and (2) it must be compatible with the client certificate's public key type via signatureSchemesForPublicKey. Additionally, PKCS#1 v1.5 and SHA-1 are explicitly rejected afterward. This is defined in RFC 8446 Section 4.4.3.

Source

Thrown at src/crypto/tls/handshake_server_tls13.go:1091

		// 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 certReq.supportedSignatureAlgorithms because it would
		// require keeping the certificateRequestMsgTLS13 around in the hs.
		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: client 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(clientSignatureContext, 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 client 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. Ensure the client cert's signature algorithm matches its public key type (RSA key uses RSA-PSS, ECDSA key uses ECDSA, Ed25519 uses ed25519).
  2. Verify the client TLS library sends signature algorithms from the server's CertificateRequest supported_signature_algorithms list.
  3. Regenerate client certificate if its key type is incompatible with the negotiated algorithms.
  4. Update the client TLS library to one that correctly implements RFC 8446 §4.4.3 signature algorithm selection.

Example fix

// Ensure client cert key type matches signature algorithm
// before: RSA cert but client sends ed25519 sig alg
// after: client cert uses ECDSA P-256, sends ecdsa_secp256r1_sha256
//
// Generate proper client cert:
// openssl ecparam -genkey -name prime256v1 -out client.key
// openssl req -new -x509 -key client.key -out client.crt
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: verify signature algorithm is compatible with cert key type
func validateCertSigAlg(pubKey crypto.PublicKey, sigAlg SignatureScheme) error {
    schemes := signatureSchemesForPublicKey(tls.VersionTLS13, pubKey)
    for _, s := range schemes {
        if s == sigAlg {
            return nil
        }
    }
    return fmt.Errorf("signature algorithm %v not compatible with public key type", sigAlg)
}

Try / catch

// Server-side: handle during client cert verification
if err := conn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "invalid signature algorithm") {
        log.Printf("client cert used unsupported signature algorithm: %v", err)
    }
}

Prevention

When it happens

Trigger: Server requested client certificates (mTLS). Client sent a CertificateVerify with a signature algorithm not in the server's supported list, or one incompatible with the client cert's key type. For example: client uses an Ed25519 cert but claims ecdsa_secp256r1_sha256; or client uses a legacy algorithm the server no longer accepts.

Common situations: Client cert key type (e.g. Ed25519, RSA-PSS) doesn't match the claimed signature algorithm; client library forces a deprecated algorithm (SHA-1 or PKCS#1 v1.5); version mismatch between client and server signature algorithm policies; client cert generated with an unusual key type the server's signatureSchemesForPublicKey doesn't recognize.

Understand the failure class

Related errors


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