Part III: Certificates · Chapter 10
Asking for a certificate: key generation and the CSR
In one sentence
You generate a key pair, keep the private key, and send the CA a certificate signing request (CSR) carrying only your public key and the names you want.
Who is this for
Level: Practitioner
On this page
The idea
- Beginner
You want a certificate for your website. The certificate will hold your public key, so the first step happens at home, on your own server: you create a key pair. The private key stays on that server. Nobody else ever needs it, not even the certificate authority.
Next you fill in a request form. It says, in effect: “Please certify that this public key belongs to www.example.com and example.com.” This form is a certificate signing request (CSR). You sign it with your private key, and send it to the CA.
The whole journey has five steps:
- Generate a key pair on the machine that will use it.
- Write the request: the names you want and your public key.
- Sign the request with your private key.
- Send the CSR to the CA. The CA checks that you really control the names (chapter 11) and then issues a certificate.
- Install the certificate next to the private key that never moved.
Why sign the request at all? The signature proves that whoever sent the CSR holds the private key that matches the public key inside it. Without it, Mallory could take Rosa’s public key, put it in a request for a name Mallory controls, and get a certificate that wrongly links the two.
A CSR is not secret: it holds only public information. It is also not a certificate. Nobody trusts a CSR, because only you have signed it. It becomes useful only after a CA has checked it and issued a certificate.
How it really works
- Developer
- Expert
What is inside a CSR?
The format is PKCS #10, published as RFC 2986 (PKCS #10). In the words of its introduction, “A certification request consists of a distinguished name, a public key, and optionally a set of attributes”, signed by the entity asking for the certificate. The structure (section 4) has two layers:
CertificationRequestInfo, the signed part:version: always 0, which openssl prints as “1 (0x0)”;subject: a distinguished name, for exampleCN=www.example.com;subjectPKInfo: the algorithm and the public key;attributes: optional extras.
signatureAlgorithmandsignature: the requester’s signature over the signed part.
Names for websites belong in the SAN extension (chapter 9). A CSR asks for extensions through an attribute called extensionRequest, defined in PKCS #9 (RFC 2985, section 5.4.2). openssl shows it as “Requested Extensions”. Windows calls it “Certificate Extensions”, with the identifier 1.2.840.113549.1.9.14.
Why does the signature matter?
RFC 2986 section 3 gives the reason in one line: “The signature on the certification request prevents an entity from requesting a certificate with another party’s public key.” This is called proof of possession. The CA verifies the CSR’s signature with the public key inside it. If the signature does not verify, the requester does not hold the matching private key, and the CA rejects the request.
This signature is a self-signature. It is not a vote of trust: it says nothing about who you are.
What does the CA do with your CSR?
The CA does not copy your CSR into a certificate. It builds a new certificate from three sources:
- Your public key, taken from the CSR unchanged.
- The names you asked for, but only those you prove you control (chapter 11). Public CAs put them in the SAN and treat the CN as optional.
- Its own profile for everything else: the validity period, key usage, extended key usage, policies and its own extensions. Public CAs must follow the Baseline Requirements, so a request for a ten-year validity or an extra purpose is simply ignored or refused.
Organisation details, such as O=Example Shop, appear in a public certificate only if the CA validated them (OV or EV). A domain-validated certificate leaves them out, whatever the CSR says.
Where do CSRs show up in practice?
- Manual ordering: you paste a PEM CSR into a CA’s web portal.
- ACME (RFC 8555): your ACME client, such as certbot, creates a key and CSR for you and sends the CSR in the “finalize” step. The RFC sends it as “the base64url-encoded version of the DER format” (section 7.4). The CSR must list the same names as the order. See chapter 20.
- Windows and Active Directory Certificate Services:
certreqand auto-enrolment create the key in the Windows key store and send a PKCS #10 request to the CA. - Private CAs and devices: the same pattern, often automated (chapter 22, chapter 25).
Which key should I generate?
For a website, an elliptic-curve key on the P-256 curve is small, fast and widely supported. RSA keys of 2048 or 3072 bits work everywhere. Public CAs accept only certain algorithms and sizes (Baseline Requirements, section 6.1.5), and they reject weak keys.
Two habits pay off:
- Generate a fresh key at every renewal, unless you have a reason not to (such as key pinning, chapter 14). A new key limits the damage if an old one leaked unnoticed.
- Protect the private key file: readable only by the service account, never in email or chat, never in a source repository. For high-value keys, use hardware that will not export them (chapter 21).
At work
- Developer
- IT ops
How do I create a key and a CSR?
With OpenSSL 3, one command creates both:
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc -keyout www.key \
-subj "/C=BE/O=Example Shop/CN=www.example.com" \
-addext "subjectAltName=DNS:www.example.com,DNS:example.com" \
-out www.csr
-newkey ec -pkeyopt ec_paramgen_curve:P-256creates a P-256 key. For RSA, use-newkey rsa:3072instead.-noencwrites the private key without a password (older OpenSSL versions call it-nodes). Servers usually need this to start unattended, so protect the file with permissions instead.-subjsets the subject.-addextadds the SAN, which is what matters for websites.www.keyis your private key. Do not open it in a chat window, a ticket or a website.
In Git Bash on Windows, the leading / in -subj can be rewritten as a Windows path. Run the command with MSYS_NO_PATHCONV=1 in front of it to prevent that.
How do I check a CSR before I send it?
openssl req -in www.csr -noout -text -verify
Certificate request self-signature verify OK
Certificate Request:
Data:
Version: 1 (0x0)
Subject: C=BE, O=Example Shop, CN=www.example.com
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:de:97:84:56:68:98:87:ab:13:b6:9e:ec:e1:43:
(4 more lines of the public key)
ASN1 OID: prime256v1
NIST CURVE: P-256
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:www.example.com, DNS:example.com
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:46:02:21:00:c6:be:5f:e2:f1:a8:dd:22:b9:d5:de:85:f1:
(3 more lines of the signature)
Check three things: the self-signature verifies, every name you need is under Requested Extensions, and the key type and size are what you intended. The file itself starts with -----BEGIN CERTIFICATE REQUEST-----. If it starts with -----BEGIN CERTIFICATE-----, you have a certificate, not a request.
How do I request many names?
For more than a couple of names, a small configuration file is easier to review and to keep in version control. It contains no secrets:
[req]
prompt = no
distinguished_name = dn
req_extensions = ext
[dn]
CN = shop.example.com
[ext]
subjectAltName = DNS:shop.example.com, DNS:api.example.com, DNS:example.com
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -noenc \
-keyout shop.key -config req.cnf -out shop.csr
openssl req -in shop.csr -noout -text | sed -n '/Attributes/,/Signature Algorithm/p'
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:shop.example.com, DNS:api.example.com, DNS:example.com
Signature Algorithm: ecdsa-with-SHA256
Does this certificate belong to my key?
When the certificate comes back, check that it holds the public key from your key pair. Hash the public key from each file and compare:
openssl pkey -in www.key -pubout | openssl sha256
openssl req -in www.csr -noout -pubkey | openssl sha256
openssl x509 -in www.crt -noout -pubkey | openssl sha256
openssl x509 -in wild.crt -noout -pubkey | openssl sha256
SHA2-256(stdin)= ffc0c984958821cfeefca9e1706dcb63e79f580063f460030841d6a20717b61c
SHA2-256(stdin)= ffc0c984958821cfeefca9e1706dcb63e79f580063f460030841d6a20717b61c
SHA2-256(stdin)= ffc0c984958821cfeefca9e1706dcb63e79f580063f460030841d6a20717b61c
SHA2-256(stdin)= 5d4c9cd343675b714f0305bedc6cbecb4b436a63b0310c8715895101c1aedd11
The key, the CSR and www.crt match. wild.crt belongs to a different key, so it will not work with www.key. The first command reads the private key file but prints only the public key’s hash. The private key itself is never shown.
A mismatch is a common reason for a server that refuses to start. nginx, for example, reports key values mismatch (nginx documentation). The same message appears when a certificate file starts with an intermediate instead of the server certificate (chapter 13).
How do I do it on Windows?
certreq builds the key inside the Windows key store, so the private key never exists as a loose file. You describe the request in an INF file, following Microsoft’s certreq reference:
[Version]
Signature=$Windows NT$
[NewRequest]
Subject = "CN=www.example.com, O=Example Shop, C=BE"
KeyAlgorithm = RSA
KeyLength = 3072
Exportable = FALSE
MachineKeySet = TRUE
RequestType = PKCS10
HashAlgorithm = sha256
[Extensions]
2.5.29.17 = "{text}"
_continue_ = "DNS=www.example.com&"
_continue_ = "DNS=example.com"
# in an elevated prompt, because MachineKeySet = TRUE creates a computer key
certreq -new request.inf request.csr
# send request.csr to the CA, receive the certificate as issued.cer
certreq -accept issued.cer
MachineKeySet = TRUEstores the key for the computer, so services such as IIS can use it.Exportable = FALSEstops anyone from exporting the private key later.certreq -acceptlinks the issued certificate to the waiting private key and installs it.
To read any CSR on Windows, use certutil -dump. Here it decodes the CSR made with openssl above:
PKCS10 Certificate Request:
Version: 1
Subject:
CN=www.example.com
O=Example Shop
C=BE
...
Attribute[0]: 1.2.840.113549.1.9.14 (Certificate Extensions)
...
Subject Alternative Name
DNS Name=www.example.com
DNS Name=example.com
Check yours
Paste a CSR into the decoder below to see its subject, its requested names and whether its self-signature verifies. It runs in your browser. A CSR is public information, but never paste a private key into any website.
Common mistakes
- “The CA creates my private key.” In the normal flow, you create it. A key that someone else generated is a key that someone else may have kept. If a portal offers to generate your key, prefer creating it on your own server.
- “The CSR contains my private key.” It contains only the public key, the names and a signature. You can share a CSR safely.
- “A CSR is a certificate, so I can install it.” Nobody trusts a CSR. Only the certificate the CA issues can be installed.
- “Everything in my CSR ends up in the certificate.” The CA decides. It uses your public key and the names you prove, and its own profile for the rest.
- “Only the CN matters.” Browsers use the SAN. Put every name in the requested SAN extension.
- “I can reuse last year’s CSR.” That reuses last year’s key. Generate a new key and CSR at renewal, or let your ACME client do it.
Why it matters to the business
- Leader
Check yourself
Your hosting provider asks you to email them your website's private key so they can order the certificate. What should you do?
RightNot quite The answer is B: Refuse, and create the key and CSR on the server yourself, or let the provider generate the key on the server that uses it
- What happened
- Refusing is right. Only the CSR needs to travel, and it holds no secrets.
- Why
- The CA needs your public key and proof that you hold the private key. The CSR's signature gives that proof, so the private key never has to leave the server.
- The rule
- The private key stays where it was generated. Send the CSR, never the key.
Show answer
Answer B Refuse, and create the key and CSR on the server yourself, or let the provider generate the key on the server that uses it
- What happened
- Refusing is right. Only the CSR needs to travel, and it holds no secrets.
- Why
- The CA needs your public key and proof that you hold the private key. The CSR's signature gives that proof, so the private key never has to leave the server.
- The rule
- The private key stays where it was generated. Send the CSR, never the key.
What does the signature on a CSR prove?
RightNot quite The answer is B: That the sender holds the private key matching the public key in the CSR
- What happened
- It proves possession of the private key, and nothing more.
- Why
- The CA verifies the signature with the public key inside the CSR. Domain control is checked separately, by validation.
- The rule
- A CSR is self-signed: it proves key possession, not identity.
Show answer
Answer B That the sender holds the private key matching the public key in the CSR
- What happened
- It proves possession of the private key, and nothing more.
- Why
- The CA verifies the signature with the public key inside the CSR. Domain control is checked separately, by validation.
- The rule
- A CSR is self-signed: it proves key possession, not identity.
You write a validity of five years into your CSR for a public TLS certificate. What happens?
RightNot quite The answer is B: The CA sets its own validity, within the public limits
- What happened
- The CA ignores your request and applies its own validity period.
- Why
- The CA builds the certificate from its own profile. Only your public key and validated names come from the CSR.
- The rule
- The CA, not the CSR, decides lifetime, key usage and policies.
Show answer
Answer B The CA sets its own validity, within the public limits
- What happened
- The CA ignores your request and applies its own validity period.
- Why
- The CA builds the certificate from its own profile. Only your public key and validated names come from the CSR.
- The rule
- The CA, not the CSR, decides lifetime, key usage and policies.
Go deeper
- RFC 2986: PKCS #10, the CSR format, in a few pages.
- RFC 2985, section 5.4.2: the
extensionRequestattribute that carries the SAN. - RFC 8555, section 7.4: how ACME clients send the CSR when they finalize an order.
- OpenSSL
reqcommand: every option for creating and inspecting requests. - Microsoft
certreq: INF syntax, SAN entries and accepting the issued certificate. - CA/Browser Forum Baseline Requirements, section 6.1: key generation and the accepted key types and sizes.
The crash course covers the CSR in lesson 5, Names, jobs and asking for a certificate.
Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.