In a TLS 1.3 handshake, which two messages does the server use to send its certificate chain and prove it holds the matching private key?
answer
- two messages, not one
- one carries, one proves
- chain travels as certificate_list
- certificate(11) then certificate_verify(15)
- TLS 1.2 server signed elsewhere
basics
~20 sCertificate carries the chain as a certificate_list of CertificateEntry structures. CertificateVerify carries a signature over the handshake transcript, made with the private key of the first certificate in that list. The chain alone proves nothing.
solid answer
~40 sA TLS 1.3 server authenticates with two consecutive handshake messages. `Certificate`, handshake type `certificate(11)`, carries the chain: its body is a `certificate_list` of `CertificateEntry` structures, the first of which is the server's own end-entity certificate. `CertificateVerify`, type `certificate_verify(15)`, carries a signature computed over a value derived from the transcript of the handshake so far, using the private key belonging to that first certificate. The split matters because a certificate is a public document — anyone can copy and replay one — so only the transcript-bound signature shows the sender actually holds the key the certificate names. `Finished` closes the flight afterwards. In TLS 1.2 the server sent no `CertificateVerify` at all; its proof of possession lived elsewhere.
code
pseudocode · 13 linesCertificate(11)
certificate_list:
entry[0] end-entity certificate for the portal host
extensions: (may carry a stapled status response)
entry[1] intermediate that signed entry[0]
# certificate naming the trust anchor omitted on purpose
CertificateVerify(15)
algorithm = ecdsa_secp256r1_sha256(0x0403)
signature = sign(private key of entry[0],
value derived from handshake transcript so far)
Finished(20)go deeper
Recall the two names and their jobs: Certificate carries the chain, CertificateVerify carries the signature that proves the key is held. Being able to say why one message is not enough is the whole of the answer at this level.
Explain the mechanics: the certificate_list of CertificateEntry structures, the first entry being the key that signs, and the signature covering the handshake transcript rather than the certificate bytes.
Use the split diagnostically. Say which of the two messages a given symptom implicates, and state the TLS 1.2 versus 1.3 difference without being prompted, since half of deployed advice silently assumes one version.
Frame it as where authentication evidence lives on the wire, and what that costs: every handshake pays for the chain in bytes and for the signature in a private-key operation, which is what makes handshake volume, not data volume, the scaling question.
## The two messages, and the order they arrive in A TLS 1.3 server that authenticates with a certificate does it with **two** consecutive handshake messages, not one: 1. **`Certificate`**, handshake type `certificate(11)`, carries the chain. Its body is a `certificate_list`: a sequence of `CertificateEntry` structures, each holding one certificate plus an extension block scoped to that entry. 2. **`CertificateVerify`**, handshake type `certificate_verify(15)`, carries a signature. The server signs a value derived from the transcript of every handshake message exchanged up to that point, using the private key belonging to the certificate in the **first** entry of the list. `Finished` then closes the server's flight, and only after that may application data flow. ## Why the chain on its own proves nothing A certificate is a public document. Every client that has ever connected holds a copy, a public log may hold one, and anyone who recorded an older handshake has one. Presenting it says only "a certificate authority signed this document"; it says nothing about whether the sender holds the private key the document names. That is exactly the gap `CertificateVerify` closes: - the signature is over the **handshake transcript**, which includes the client's own freshly generated `ClientHello`, so a signature lifted from a recorded handshake will not verify in this one; - it is made with the key of the **first** certificate in `certificate_list`, which is why the ordering rule exists — the first entry is the sender's own certificate, never an intermediate; - the message names the signature scheme that was used, and that scheme has to be one the client said it would accept. Without the second message, an attacker who simply replays a captured `Certificate` message would be indistinguishable from the real server. ## What each entry in the list holds - The **first** `CertificateEntry` is the server's end-entity certificate — the one whose key signs `CertificateVerify`. - Following entries are the intermediate certificates that link it upward, each normally certifying the entry immediately before it. - A certificate that names a trust anchor the peers are expected to hold already may be omitted from the list entirely. - Every entry carries its own extension block; that block is where TLS 1.3 places a stapled status response, per certificate rather than per handshake. ## TLS 1.2 kept the server's proof somewhere else | | TLS 1.2 | TLS 1.3 | |---|---|---| | Server sends `Certificate` | yes | yes | | Server sends `CertificateVerify` | no | yes | | Where the server proves key possession | in `server_key_exchange (12)` for ephemeral suites; implicitly, by decrypting the client's key material, for static RSA key transport | in `CertificateVerify` | | Who else sends `CertificateVerify` | the client only, answering a `CertificateRequest` | the client, answering a `CertificateRequest` | So "the server sends `CertificateVerify`" is a **TLS 1.3** statement. The guarantee existed in TLS 1.2 too, but it lived in a different message, and the name `CertificateVerify` referred to the client's message alone. Dropping the version is the most common inaccuracy on this material. ## Reading the pair when a handshake goes wrong Splitting the two jobs splits the failures, which is what makes the distinction practical rather than trivia: - a problem with **what was sent** — a missing intermediate, entries in the wrong order, a certificate naming no host the client asked for — is a `Certificate` problem, and is visible to anything that can print the chain the server actually put on the wire; - a problem with **the proof** — a signature that does not verify, or a scheme the client never offered — is a `CertificateVerify` problem, and re-issuing certificates will not touch it; - a server holding no certificate compatible with what the client offered fails before either message is built. ## What the pair is not - It is **not path validation**. The server puts a list on the wire; the client builds and checks a path from it up to an anchor it already trusts. Those are different operations with different failure modes. - It is **not a statement about revocation**. Neither message asserts the certificate is still valid today; a status response, when one is present at all, rides as an extension. - It is **not client authentication**. The client has its own `Certificate` and `CertificateVerify` pair, but sends it only in answer to a `CertificateRequest`. - It **does not carry the private key**. Nothing in either message reveals it. The signature is the only evidence of that key that ever crosses the wire.
- If a TLS 1.2 server sent no CertificateVerify, where did it prove it held the private key?For ephemeral suites, in `server_key_exchange (12)`: the server signed the key-exchange parameters together with both peers' random values, and that signature was verified against the certificate it had just sent. Under static RSA key transport there was no signature at all — the server demonstrated possession by being able to decrypt the key material the client encrypted to its public key. TLS 1.3 removed that second path and moved the proof into one explicit message.
- A TLS 1.3 server sends Certificate but its CertificateVerify never arrives. What has the client established?Nothing about the peer's identity. It holds a chain it may well be able to validate, but a chain is public data that any party can transmit. Without a transcript-bound signature made by the key in the first `CertificateEntry`, the client has no evidence that the party it is talking to holds that key, so the handshake cannot be completed.
saying these in an interview costs you the question
- Says the certificate alone proves the server holds the private key
- Thinks one message carries both the chain and the signature
- Believes a TLS 1.2 server also sends CertificateVerify
- Calls the chain a single certificate rather than a certificate_list
- Thinks the private key is transmitted during the handshake