What's inside a CSR, byte by byte
A certificate signing request is one of those artifacts everyone generates and almost nobody reads. You run a command, paste the -----BEGIN CERTIFICATE REQUEST----- block into a CA's form, and a certificate comes back. But a CSR is a small, fully specified data structure, and understanding what is actually inside it explains a surprising number of certificate problems. Let us open one up.
The outer wrapper: PEM and DER
The text block you copy is PEM: base64-encoded bytes between header and footer lines. Decode that base64 and you get DER, the binary encoding of an ASN.1 structure defined by the PKCS#10 standard. ASN.1 is a way of describing structured data; DER is one canonical way of serializing it to bytes. So "the CSR" is really an ASN.1 structure that has been DER-encoded and then base64-wrapped for easy copy-paste.
The PKCS#10 structure has three top-level parts:
- CertificationRequestInfo — the actual content: subject, public key, attributes.
- signatureAlgorithm — which algorithm signed the request.
- signature — the signature itself.
The request signs its own content. That is the first non-obvious thing: a CSR is self-signed. We will come back to why.
Part 1: the subject
The subject is the identity being requested, expressed as a Distinguished Name — an ordered set of attribute/value pairs:
CN(Common Name) — historically the hostname, e.g.example.com.O,OU— organization and organizational unit.L,ST,C— locality, state, country.
A long-standing source of confusion lives here. Browsers stopped trusting the Common Name for hostname matching years ago; they read the Subject Alternative Name instead. The CN alone is not enough. If your CSR has a CN but no SAN, the issued certificate may be rejected by modern clients. The SAN is not part of the subject DN — it rides in the attributes section as a requested extension, which is the next part.
Part 2: the public key
The CSR carries a SubjectPublicKeyInfo block: an identifier for the key type and parameters (RSA 2048, RSA 4096, ECDSA P-256, and so on) followed by the public key itself. Critically, the CSR contains only the public key. The private key never leaves your server, never appears in the CSR, and must never be sent to the CA. This separation is the entire security model: the CA certifies a public key while you retain sole control of its private counterpart.
This is also why the key type you chose when generating the CSR is locked in. The CA issues a certificate for the key in the request; you cannot change RSA to ECDSA after the fact without a new CSR.
Part 3: the attributes (where the SAN lives)
PKCS#10 allows a set of attributes, and the important one is extensionRequest. This is where a client asks the CA to include specific X.509 extensions in the final certificate — most importantly the Subject Alternative Name list of DNS names and IP addresses the certificate should cover. Multi-domain and wildcard certificates are requested here.
A caveat worth knowing: the CA is not obligated to honor requested extensions, and public CAs commonly override or ignore some of them, applying their own policy. The CSR proposes; the CA disposes.
The self-signature: what it does and does not prove
The CSR is signed with the private key corresponding to the public key inside it. This proves one specific thing: whoever produced the CSR possesses the private key for the enclosed public key — proof of possession. It stops someone from requesting a certificate for a public key they do not control.
It proves nothing about the identity in the subject. The CSR's self-signature does not vouch for the hostname or organization; that is the CA's job, through domain or organization validation performed separately. So a CSR's own signature and a CA's validation are two entirely different checks, and conflating them is a common misconception.
Reading one yourself
To see all of this in a real request without trusting a remote service with it, the CSR generator builds a CSR in the browser and lets you set the subject and SAN explicitly, so you can watch how each field maps into the structure. To inspect a finished certificate that came back from a CA and confirm the SAN and key match what you asked for, the SSL decoder parses it locally.
Once you can read a CSR, a lot of certificate friction stops being mysterious: a missing SAN, a key type you did not intend, a subject the CA rewrote. It is all right there in a few hundred bytes. Build one and read it field by field with the CSR generator to check yours.