Skip to content
Lesson 9 of 14

Step 1 of 5 · Reading · ~2 min

Read

TLS 1.3 Handshake

CertificateVerify — Proving Possession

The Certificate message lets the server show you a chain of X.509 documents. But anyone can forward someone else's cert. CertificateVerify is the cryptographic proof that the server actually holds the private key for the leaf certificate.

The signature input (RFC 8446 §4.4.3)

The signed bytes are not just the transcript hash. They are this fixed structure:

sig_input =
    64 octets of 0x20                            // padding so legacy verifiers refuse
||  context_string                                // ASCII, see below
||  0x00                                         // separator
||  Transcript-Hash(Handshake Context, Certificate)

Two context strings, exactly:

  • "TLS 1.3, server CertificateVerify" — server's signature
  • "TLS 1.3, client CertificateVerify" — client's signature (mTLS)

Including the context string defeats a cross-protocol attack: a signing oracle in some unrelated protocol cannot be tricked into signing something that looks like a TLS 1.3 transcript.

The 64 bytes of 0x20 (ASCII space) at the front mean a TLS 1.2 server that doesn't know about TLS 1.3 will see b" " * 64 + ... and refuse — defence against version confusion.

Allowed signature algorithms

RFC 8446 §4.2.3 lists the schemes a TLS 1.3 cert may use. Mandatory-to-implement:

  • rsa_pkcs1_sha256/384/512 — only for certificates (not the signature itself in 1.3)
  • rsa_pss_rsae_sha256/384/512 — RSA-PSS with the standard salt = hash length
  • ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384
  • ed25519 (RFC 8032) — most modern deployments where supported

PKCS#1 v1.5 signatures are not allowed as the CertificateVerify signature in TLS 1.3 — only inside the cert. This is to stop padding-oracle attacks like Bleichenbacher / ROBOT.

Verifying

python

Replay & cross-connection safety

The transcript hash includes ClientHello.random and ServerHello.random (each 32 fresh bytes). So even if the same cert is used to sign a million handshakes, every signed payload is different — replay across connections is impossible.

The signature only covers messages up to and including Certificate. The Finished MAC then covers everything including CertificateVerify itself, so any tampering in flight is caught.

Up nextRecord LayerRecord Layer & Resumption

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…