After a mutual TLS handshake, where should a service read the caller's identity from, and why not from the request payload?
answer
- one authenticated name per connection
- the payload is still caller-chosen data
- nobody dialled the client by name
- no protocol name check on a client leaf
- read it from the subjectAltName entry
basics
~20 sFrom the verified client leaf certificate, normally a subjectAltName entry: that is the only name the handshake authenticated. An identifier inside the request is unauthenticated input, so a disagreement between the two must fail the request rather than be resolved silently.
solid answer
~50 sThe authenticated identity is the name in the client's verified leaf certificate, read from a `subjectAltName` entry. That is the only name the handshake established: TLS proved the peer holds the private key for that leaf and that the chain reached an anchor the service trusts. An identifier the caller puts in its own request is just data the caller chose, and it carries no more weight on a mutual connection than on any other. The important asymmetry is that nothing in the protocol checks a client certificate's name against anything, because the client is not being dialled by name; the service has to do the mapping itself. So read the name from the certificate, map it to a principal, and if the payload also carries one, treat a mismatch as a hard failure rather than silently preferring either side.
code
pseudocode · 15 lineson handshake_complete(connection):
chain = connection.verified_peer_chain // TLS validated path and signature
if chain is empty:
reject connection // no certificate means no identity
name = subjectAltName_entry_of(chain.leaf) // the only authenticated name
principal = lookup_principal(name)
if principal is none:
reject connection // a valid chain is not an account
connection.identity = principal
on request(connection, message):
if message.claimed_operator exists
and message.claimed_operator != connection.identity:
reject request // never silently prefer either side
handle(message, as: connection.identity)go deeper
Know that the identity comes from the client's certificate, not from anything inside the request, and that a request field naming a user is data the caller chose.
Explain what the handshake established: a chain the service accepted and proof of key possession. Turning that into a named caller means reading the subjectAltName entry from the verified leaf.
Demonstrate the judgment: nothing in the protocol checks a client leaf's name, so the mapping is yours, an unknown name is a rejection, and a payload that disagrees fails the request rather than being reconciled.
Consider where identity should live across the estate. Which anchors are trusted determines how much work the name check is doing, and a broad anchor turns every service into the last line of defence.
## What the handshake has decided, and what it has not When a mutual handshake completes, the service holds two facts about the peer: - a certificate chain it was willing to accept, ending at a trust anchor it already held; - proof that the peer holds the private key for the leaf in that chain, because the peer signed this connection's transcript with it. That is the whole result. Note what is missing: **which** holder this is. A chain that validates says only that some authority the service trusts issued the leaf. If the service trusts an authority that issues broadly, every certificate that authority ever issued validates just as well. The step from a valid chain to a named caller is the application's, and it is made by reading the name out of the certificate. ## The asymmetry nobody expects On the server side of a handshake the name check is automatic in the sense that the client knows which name it wanted: it dialled one, and it compares that against the certificate it received. A mismatch is a failure on the spot. On the client side there is no such expectation. The service did not dial the crane; the crane connected to it. The protocol therefore has nothing to compare the client leaf's name against and performs no name check at all. It validates the path and the signature and hands the application a verified certificate. **Everything about which peer this is comes afterwards, from code the service wrote.** This is why a service can be fully mutually authenticated and still have no idea who is calling. Both statements are true at once, and reconciling them is exactly what a senior candidate is being asked to do. ## Reading the name The name is taken from a `subjectAltName` entry in the verified leaf. Practical points: - **Read it from the verified chain**, the one the TLS layer produced, not from a copy the application parsed out of somewhere else. - **Decide which entry type you accept** and apply it consistently, rather than taking whichever entry appears first. - **Map, do not match loosely.** Translate the entry into a principal the service already knows, so an unknown name is a rejection rather than an implicit new identity. - **Do not reconstruct identity from the chain's issuer.** The issuer says who vouched, never who is calling. ## When the payload disagrees A crane control link usually carries an operator or equipment identifier in the message itself, because the application had one long before certificates were introduced. Once both exist, three handlings are possible and only one is defensible: 1. **Prefer the payload.** The certificate has then authenticated nobody in particular, because any valid peer can claim to be any other. This is the failure the whole exercise was meant to prevent. 2. **Prefer the certificate and rewrite the payload silently.** Safer, but it hides the disagreement. A client sending the wrong identifier is either misconfigured or probing, and both are things you want to see. 3. **Reject on mismatch.** The certificate name decides, and a request that disagrees with it never executes. The disagreement is surfaced as a failure rather than absorbed. The third is the answer, and the reasoning matters more than the rule: on an authenticated connection the two values should never differ, so a difference is evidence of a defect or an attempt. Absorbing evidence is not a safety measure. ## What the service still owes The certificate name is an identity, not a permission. Mapping it to a principal is where the service decides what that principal may do, and a name that maps to nothing is a refusal rather than a default. Two further habits pay for themselves: - **Log the certificate name, not the payload identifier**, so that an audit trail reflects what was actually authenticated. - **Fail closed when the name is absent.** A connection carrying no client certificate should never fall through to the payload identifier, because that path quietly converts a mutually authenticated service into an unauthenticated one. The compact way to say all of it: TLS tells you the caller holds a key and a certificate; only the name in that certificate tells you which caller, and nothing the caller sends afterwards can upgrade itself into that role.
- Why does the protocol check the server's name but not the client's?Because the check needs an expectation to compare against. A client dialled a specific name and can compare it with what arrived. A service did not dial anything: a connection simply appeared, so there is no expected name in the protocol's hands. Validation of the chain and the signature happens either way; only the name comparison has no counterpart.
- What goes wrong if a service trusts a broadly issuing authority for client certificates?Validity stops distinguishing callers. Every certificate that authority ever issued builds a valid path, so accepting any valid chain accepts far more peers than intended. The name check is then the only thing separating the intended caller from everyone else, which makes reading and mapping the name mandatory rather than a refinement.
- Should a mismatch between the certificate name and a payload identifier be logged or rejected?Both, and rejection first. The request does not execute, and the disagreement is recorded with the authenticated name attached. Silently preferring the certificate would keep the system safe while hiding a misconfigured or probing client, which is the kind of signal that only ever appears once before it matters.
saying these in an interview costs you the question
- Thinks a valid chain by itself identifies the caller
- Trusts an identifier in the payload because the connection is authenticated
- Believes TLS matches a client certificate name against something automatically
- Reads the caller identity from the chain's issuer
- Silently prefers one identity source when the two disagree
- Falls back to the payload identifier when no client certificate is present