Introduction

A Certificate Signing Request (CSR) contains the public key and identifying information needed for a Certificate Authority to issue your SSL certificate. Errors in CSR generation lead to rejected requests, certificates with wrong names, or security weaknesses. Understanding CSR components and proper generation methods ensures smooth certificate issuance.

Symptoms

  • CA rejects CSR with "invalid CSR" error
  • Certificate issued with wrong Common Name or missing SANs
  • CSR doesn't match the private key you intended
  • Key size too small (CA requires minimum size)
  • OpenSSL error during CSR generation
  • Missing Subject Alternative Names for multiple domains
  • Certificate doesn't cover all required hostnames

Common Causes

  • Wrong subject format or missing required fields
  • Missing Subject Alternative Names for multi-domain certificates
  • Key size below CA minimum (often 2048 bits)
  • Using wrong private key file
  • OpenSSL command syntax errors
  • Country code wrong format (must be 2 letters)
  • Special characters in subject fields not properly escaped
  • Generated CSR but saved wrong file

Step-by-Step Fix

Step 1: Generate Basic CSR Correctly

```bash # Generate new private key and CSR together openssl req -new -newkey rsa:4096 -nodes \ -keyout example.com.key \ -out example.com.csr \ -subj "/C=US/ST=California/L=San Francisco/O=Example Inc/OU=IT/CN=example.com"

# Or generate CSR from existing key openssl req -new \ -key existing.key \ -out example.com.csr \ -subj "/C=US/ST=California/L=San Francisco/O=Example Inc/CN=example.com"

# Subject field meanings: # C = Country (2-letter code) # ST = State or Province # L = Locality (City) # O = Organization # OU = Organizational Unit (optional) # CN = Common Name (main domain) ```

Step 2: Add Subject Alternative Names

```bash # Modern certificates require SANs for multiple domains # CN alone is insufficient

# Create config file for SANs cat > san.cnf << EOF [req] default_bits = 4096 distinguished_name = req_distinguished_name req_extensions = req_ext prompt = no

[req_distinguished_name] C = US ST = California L = San Francisco O = Example Inc CN = example.com

[req_ext] subjectAltName = @alt_names

[alt_names] DNS.1 = example.com DNS.2 = www.example.com DNS.3 = api.example.com DNS.4 = mail.example.com EOF

# Generate CSR with SANs openssl req -new -newkey rsa:4096 -nodes \ -keyout example.com.key \ -out example.com.csr \ -config san.cnf ```

bash
# Or use -addext for OpenSSL 1.1.1+
openssl req -new -newkey rsa:4096 -nodes \
  -keyout example.com.key \
  -out example.com.csr \
  -subj "/C=US/ST=California/L=San Francisco/O=Example Inc/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:www.example.com,DNS:api.example.com"

Step 3: Generate Wildcard CSR

```bash # Wildcard CSR with root domain openssl req -new -newkey rsa:4096 -nodes \ -keyout wildcard.key \ -out wildcard.csr \ -subj "/C=US/ST=State/L=City/O=Organization/CN=*.example.com" \ -addext "subjectAltName=DNS:*.example.com,DNS:example.com"

# Note: Wildcard (*.example.com) covers one level only # Does NOT cover api.staging.example.com (two levels) # Does NOT cover example.com (root) without explicit SAN ```

Step 4: Verify CSR Before Submission

```bash # Check CSR details openssl req -in example.com.csr -noout -text

# Verify subject openssl req -in example.com.csr -noout -subject

# Check SANs openssl req -in example.com.csr -noout -text | grep -A 1 "Subject Alternative Name"

# Verify public key openssl req -in example.com.csr -noout -pubkey

# Verify CSR matches private key openssl req -in example.com.csr -noout -modulus | openssl md5 openssl rsa -in example.com.key -noout -modulus | openssl md5 # Hashes must match ```

Step 5: Check Key Size Requirements

```bash # Check current key size openssl rsa -in example.com.key -text -noout | grep "Private-Key"

# Most CAs require minimum 2048 bits # Some require 4096 for EV certificates # 1024 bits is no longer acceptable

# Generate with proper size openssl genrsa -out example.com.key 4096 ```

Step 6: Handle Special Characters

```bash # Special characters in subject fields need escaping # Comma must be escaped with backslash

openssl req -new -key example.com.key \ -out example.com.csr \ -subj "/C=US/ST=California/L=San Francisco/O=Example\, Inc/CN=example.com"

# Or use config file to avoid escaping issues cat > subject.cnf << EOF [req_distinguished_name] C = US ST = California L = San Francisco O = Example, Inc CN = example.com EOF ```

Step 7: Fix Common Generation Errors

```bash # "invalid CSR format" error # Usually means OpenSSL syntax issue # Check for typos in subject string

# Wrong: Missing quotes or wrong format openssl req -new -key key.pem -out csr.pem -subj C=US ST=State # WRONG

# Correct: Proper quoting openssl req -new -key key.pem -out csr.pem -subj "/C=US/ST=State" # CORRECT

# "unable to load Private Key" error # Key file corrupted or wrong format openssl rsa -in key.pem -check

# "no object identifier" error # Config file missing required sections ```

Step 8: Submit CSR Correctly

```bash # After verifying CSR is correct:

# For Let's Encrypt (no manual CSR needed usually) certbot certonly -d example.com -d www.example.com

# For commercial CAs: # 1. Copy CSR content (base64 text between BEGIN/END) # 2. Paste into CA's order form # 3. Select certificate type (DV, OV, EV) # 4. Complete validation process

# Display CSR for copying cat example.com.csr ```

Step 9: Keep Key and CSR Together

```bash # Always keep key file matched with CSR # Certificate will only work with this specific key

# Organize by domain and date mkdir -p /root/certs/example.com-2026/ mv example.com.key /root/certs/example.com-2026/ mv example.com.csr /root/certs/example.com-2026/

# When certificate arrives, add to same directory mv example.com.crt /root/certs/example.com-2026/ ```

Common Pitfalls

  • Generating CSR without SANs for multi-domain certificate
  • Using 1024-bit key (too small, rejected by modern CAs)
  • Wrong country code format (must be exactly 2 letters)
  • Not escaping special characters in organization name
  • CSR and key mismatched (generated separately)
  • Missing root domain in wildcard certificate SANs
  • Not verifying CSR before submitting to CA

Best Practices

  • Always use at least 2048-bit keys (4096 for high security)
  • Include all required domains in Subject Alternative Names
  • Verify CSR matches private key before submission
  • Keep key and CSR organized together
  • Document CSR parameters for future renewals
  • Test CSR generation with config file approach for complex subjects
  • Include root domain when requesting wildcard certificates
  • SSL Private Key Mismatch
  • SSL Certificate Name Mismatch
  • SSL Certificate Chain Incomplete
  • Let's Encrypt Challenge Failed