<!-- https://pkizerotohero.com/handbook/csr/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> What a CSR (PKCS #10) contains, why your private key never leaves you, and how to create and check one with openssl req and Windows certreq.

Source: https://pkizerotohero.com/handbook/csr/ · Last reviewed: 2026-10-20

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

- [Developer](https://pkizerotohero.com/start/#developer)
- [IT ops](https://pkizerotohero.com/start/#itops)
- [Beginner](https://pkizerotohero.com/start/#beginner)
- [Expert](https://pkizerotohero.com/start/#expert)
- [Leader](https://pkizerotohero.com/start/#leader)

Level: **Practitioner**

- [New to this? Start with The idea](https://pkizerotohero.com/handbook/csr/#the-idea)
- [Developer? Jump to How it really works](https://pkizerotohero.com/handbook/csr/#how-it-really-works)
- [IT ops? At work](https://pkizerotohero.com/handbook/csr/#at-work)
- [Leader? Why it matters](https://pkizerotohero.com/handbook/csr/#why-it-matters-to-the-business)

## 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](https://pkizerotohero.com/handbook/glossary/#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](https://pkizerotohero.com/handbook/glossary/#csr) (CSR). You sign it with your private key, and send it to the CA.

The whole journey has five steps:

1. **Generate** a key pair on the machine that will use it.
2. **Write the request**: the names you want and your public key.
3. **Sign the request** with your private key.
4. **Send the CSR** to the CA. The CA checks that you really control the names ([chapter 11](https://pkizerotohero.com/handbook/domain-validation/)) and then issues a certificate.
5. **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.

In the game

In the game: Rosa's petition

In Level 10, Rosa visits the Petition Office. She makes her key pair at home, writes a petition with her name and her public key, signs it, and hands over only the petition. The private key never leaves her hands.

Where the analogy stops being true: a petition signed by a princess carries her authority, but a CSR’s signature proves only one thing, that the sender holds the private key. It does not prove who the sender is or that they own the names in it. The CA must check that separately.

## 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](https://www.rfc-editor.org/rfc/rfc2986#section-4)) has two layers:

- `CertificationRequestInfo`, the signed part:
    - `version`: always 0, which openssl prints as “1 (0x0)”;
    - `subject`: a distinguished name, for example `CN=www.example.com`;
    - `subjectPKInfo`: the algorithm and the public key;
    - `attributes`: optional extras.
- `signatureAlgorithm` and `signature`: the requester’s signature over the signed part.

Names for websites belong in the SAN extension ([chapter 9](https://pkizerotohero.com/handbook/names-and-key-usage/)). A CSR asks for extensions through an attribute called `extensionRequest`, defined in PKCS #9 ([RFC 2985, section 5.4.2](https://www.rfc-editor.org/rfc/rfc2985#section-5)). openssl shows it as “Requested Extensions”. Windows calls it “Certificate Extensions”, with the identifier 1.2.840.113549.1.9.14.

*Diagram: Three columns. On the left, your server holds the private key, marked as staying there, and the public key. An arrow takes the public key into the CSR in the middle, which contains the names, the public key and your signature. An arrow sends the CSR to the certificate authority on the right, which checks the CSR's signature and that you control the names, then issues a certificate with the names, the public key and the CA's signature. An arrow returns the certificate to your server, where it is installed beside the private key. A note says the private key is never sent to anyone.*

Only the public key and the names travel. The private key never leaves your server.

### Why does the signature matter?

[RFC 2986 section 3](https://www.rfc-editor.org/rfc/rfc2986#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](https://pkizerotohero.com/handbook/glossary/#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](https://pkizerotohero.com/handbook/domain-validation/)). 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](https://cabforum.org/working-groups/server/baseline-requirements/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](https://www.rfc-editor.org/rfc/rfc8555#section-7.4)). The CSR must list the same names as the order. See [chapter 20](https://pkizerotohero.com/handbook/acme/).
- **Windows and Active Directory Certificate Services**: `certreq` and 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](https://pkizerotohero.com/handbook/private-ca/), [chapter 25](https://pkizerotohero.com/handbook/device-identity/)).

### 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](https://pkizerotohero.com/handbook/cross-signing/)). 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](https://pkizerotohero.com/handbook/hsm-and-key-ceremonies/)).

## At work

- Developer
- IT ops

### How do I create a key and a CSR?

With OpenSSL 3, one command creates both:

```bash
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-256` creates a P-256 key. For RSA, use `-newkey rsa:3072` instead.
- `-noenc` writes 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.
- `-subj` sets the subject. `-addext` adds the SAN, which is what matters for websites.
- `www.key` is 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?

```bash
openssl req -in www.csr -noout -text -verify
```

```text
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:

```text
[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
```

```bash
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'
```

```text
        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:

```bash
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
```

```text
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](https://nginx.org/en/docs/http/configuring_https_servers.html)). The same message appears when a certificate file starts with an intermediate instead of the server certificate ([chapter 13](https://pkizerotohero.com/handbook/certificate-chains/)).

### 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](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certreq_1):

```text
[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"
```

```powershell
# 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 = TRUE` stores the key for the computer, so services such as IIS can use it.
- `Exportable = FALSE` stops anyone from exporting the private key later.
- `certreq -accept` links 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:

```text
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.

*Interactive tool: CSR decoder (runs in the browser at [/tools/csr/](https://pkizerotohero.com/tools/csr/))*

## 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

Why it matters to the business

The private key is the asset, not the certificate

A certificate is public and can be replaced in minutes. The private key is what lets a server, or an attacker, act in your name. Good practice is simple to state: generate each key on the system that uses it, never send it by email or store it in shared folders, and replace it at every renewal. Ask your teams and suppliers whether any process moves private keys between people or systems, and who can read them. That answer tells you more about your exposure than the number of certificates you own.

## Check yourself

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?

1. Email it inside a password-protected zip file
2. Refuse, and create the key and CSR on the server yourself, or let the provider generate the key on the server that uses it
3. Email the certificate instead, because it contains 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.

Check yourself

What does the signature on a CSR prove?

1. That the CA has approved the request
2. That the sender holds the private key matching the public key in the CSR
3. That the sender owns the domain names listed in the CSR

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.

Check yourself

You write a validity of five years into your CSR for a public TLS certificate. What happens?

1. The certificate is valid for five years
2. The CA sets its own validity, within the public limits
3. The CA must ask a browser vendor for permission

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](https://www.rfc-editor.org/rfc/rfc2986): PKCS #10, the CSR format, in a few pages.
- [RFC 2985, section 5.4.2](https://www.rfc-editor.org/rfc/rfc2985#section-5): the `extensionRequest` attribute that carries the SAN.
- [RFC 8555, section 7.4](https://www.rfc-editor.org/rfc/rfc8555#section-7.4): how ACME clients send the CSR when they finalize an order.
- [OpenSSL `req` command](https://docs.openssl.org/master/man1/openssl-req/): every option for creating and inspecting requests.
- [Microsoft `certreq`](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certreq_1): INF syntax, SAN entries and accepting the issued certificate.
- [CA/Browser Forum Baseline Requirements](https://cabforum.org/working-groups/server/baseline-requirements/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](https://pkizerotohero.com/course/names-and-requests/).

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/handbook/csr/).

Last reviewed 20 October 2026Edition 0.9

## Keep going

Crash course: [Lesson 5: Names, jobs and asking for a certificate](https://pkizerotohero.com/course/names-and-requests/)

### How-to guides

- [How to check that a private key matches a certificate](https://pkizerotohero.com/guides/check-key-matches-certificate/)
- [How to create a key and a CSR with OpenSSL (with SANs)](https://pkizerotohero.com/guides/create-csr-openssl/)
- [How to create a CSR on Windows (certreq and IIS)](https://pkizerotohero.com/guides/create-csr-windows/)
- [How to create a CSR with Java keytool](https://pkizerotohero.com/guides/create-csr-java-keytool/)

### Tools

- [CSR decoder](https://pkizerotohero.com/tools/csr/): Check a certificate signing request before you send it to a CA.
- [Certificate decoder](https://pkizerotohero.com/tools/decoder/): Paste a PEM certificate and read every field in plain words.

### Topics

- [Certificates](https://pkizerotohero.com/topics/certificates/)
