golang/go · critical

tls: invalid signature by the server certificate: {err}

Error message

tls: invalid signature by the server certificate: {err}

What it means

CertificateVerify signature verification failed: the server's signature over the transcript does not validate against the leaf certificate's public key. Go sends `decrypt_error`. This is the core authenticity check of the TLS 1.3 handshake; failure means the server does not hold the private key for the certificate it presented (MITM) or the handshake transcript was tampered with.

Source

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

	// 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
	}

	return nil
}

func (hs *clientHandshakeStateTLS13) readServerFinished() error {
	c := hs.c

	// finishedMsg is included in the transcript, but not until after we
	// check the client version, since the state before this message was
	// sent is used during verification.
	msg, err := c.readHandshake(nil)
	if err != nil {

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Investigate as a potential MITM — do NOT bypass this check under any circumstances.
  2. Verify the server's private key matches its certificate (re-issue/re-install the correct key pair).
  3. Compare the certificate chain presented over a trusted network vs. the failing one.
  4. Check for TLS-intercepting proxies, captive portals, or corporate firewalls that substitute certificates.
Defensive patterns

Strategy: try-catch

Try / catch

// Signature verification failure may indicate MITM — never bypass.
if err := conn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "invalid signature by the server certificate") {
        securityLog.Printf("possible MITM against %s: %v", addr, err)
    }
    return err
}

Prevention

When it happens

Trigger: verifyHandshakeSignature returns an error when checking certVerify.signature against c.peerCertificates[0].PublicKey over the signed transcript. Any TLS 1.3 handshake with a bad signature.

Common situations: Active MITM (the classic TLS attack signal), a misconfigured server using the wrong private key for its certificate, a certificate chain reissued without matching key, or transcript tampering by a proxy.

Understand the failure class

Related errors


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