How to Generate Certificates from CSRs with mkcert: A Complete Guide
Yes, mkcert supports generating certificates from Certificate Signing Requests (CSRs) using the -csr flag, which creates a locally-trusted development certificate signed by the mkcert root CA.
The FiloSottile/mkcert tool is widely used for creating locally-trusted development certificates, and its CSR signing capability allows you to generate certificates from private keys that never leave your system. This feature is particularly useful when you need to maintain control of your private keys while still obtaining a trusted certificate for local development.
How the -csr Flag Works in mkcert
When you invoke mkcert with the -csr flag, the tool reads a PEM-encoded Certificate Signing Request, validates its cryptographic signature, and issues a new certificate signed by the local mkcert Certificate Authority (CA). The resulting certificate inherits the Subject and Subject Alternative Names (SANs) specified in the original CSR.
According to the source code in cert.go, the makeCertFromCSR function handles this process by:
- Parsing the CSR using
x509.ParseCertificateRequest - Verifying the CSR signature with
CheckSignature - Building a certificate template that copies the CSR's subject and DNS names
- Signing the final certificate with the mkcert CA key
Usage Constraints and Limitations
The CSR functionality in mkcert comes with specific constraints enforced during argument parsing in main.go. Understanding these limitations prevents common errors:
Allowed combinations:
-install— to install the mkcert root CA in system trust stores-cert-file— to specify a custom output filename for the generated certificate
Prohibited combinations:
-pkcs12— PKCS#12 bundle generation is disabled with CSR mode-ecdsa— ECDSA key generation is irrelevant when signing existing CSRs-client— Client certificate generation conflicts with CSR signing- Host arguments — Positional hostname arguments are not permitted when using
-csr
The flag must appear before any positional arguments, though no positional arguments are allowed when processing CSRs.
Step-by-Step: Generating a Certificate from a CSR
Step 1: Create the CSR
First, generate a private key and Certificate Signing Request using your preferred tool. This example uses OpenSSL to create a 2048-bit RSA key:
openssl req -new -nodes -newkey rsa:2048 \
-keyout example.key \
-out example.csr \
-subj "/CN=example.test" \
-addext "subjectAltName = DNS:example.test, DNS:*.example.test"
The private key (example.key) remains on your system, while the CSR (example.csr) contains the public key and requested certificate details.
Step 2: Sign the CSR with mkcert
Use mkcert to generate the certificate from your CSR:
mkcert -csr example.csr -cert-file example.pem
This command reads example.csr, validates its signature, and outputs example.pem — a certificate signed by your local mkcert CA that is automatically trusted by browsers on your development machine.
Step 3: Install the Root CA (Optional)
If you haven't already installed the mkcert root CA in your system trust store:
mkcert -install
This step ensures that certificates generated by mkcert, including those created from CSRs, are trusted by your operating system and browsers.
Implementation Details
The CSR functionality is implemented across two primary source files in the FiloSottile/mkcert repository:
Argument Parsing (main.go)
Lines 39-44 and 64-67 in main.go define the -csr flag and enforce the constraint that it cannot be combined with incompatible flags like -pkcs12 or host arguments:
// From main.go - flag definition
csrFlag = flag.String("csr", "", "CSR file to use for certificate generation")
Certificate Generation (cert.go)
The makeCertFromCSR function (lines 9-46 in cert.go) handles the cryptographic operations:
- Parsing: The CSR is decoded using
pem.Decodeand parsed withx509.ParseCertificateRequest - Validation: The signature is verified using
CheckSignatureto ensure the CSR hasn't been tampered with - Template Construction: A certificate template is built copying the Subject, DNS names, and IP addresses from the CSR
- Signing: The final certificate is signed using the mkcert CA's private key via
x509.CreateCertificate
Summary
- mkcert supports CSR-based certificate generation through the
-csrflag, creating locally-trusted certificates without exposing private keys. - Strict flag compatibility applies:
-csrworks only with-installand-cert-file, and cannot combine with-pkcs12,-ecdsa,-client, or host arguments. - Implementation resides in
main.go(argument validation) andcert.go(makeCertFromCSRfunction), following standard X.509 CSR parsing and signing workflows. - Workflow: Create CSR with external tool → Sign with
mkcert -csr <file>→ Use resulting PEM certificate in development environment.
Frequently Asked Questions
Can I use mkcert to sign CSRs with my own existing CA instead of the mkcert-generated CA?
No, mkcert is designed specifically to work with its own automatically generated local CA. The makeCertFromCSR function in cert.go always uses the mkcert CA private key stored in the mkcert data directory. If you need to sign CSRs with a custom CA, you would need to use OpenSSL or another certificate management tool.
Why does mkcert prevent using -csr with the -pkcs12 or -client flags?
These restrictions exist because the -csr flag implies you already have a private key (embedded in or associated with the CSR), making -pkcs12 (which bundles a new key and certificate) redundant. Similarly, -client generates client authentication certificates with specific Extended Key Usage attributes, which conflicts with the CSR workflow where the certificate type is determined by the CSR's own attributes. The validation logic in main.go enforces these mutual exclusivity rules.
Does mkcert verify the CSR signature before signing it?
Yes, mkcert validates the CSR signature before issuing a certificate. In cert.go, the makeCertFromCSR function calls CheckSignature on the parsed CSR to verify that the request hasn't been tampered with and that the requester possesses the corresponding private key. If signature verification fails, mkcert will exit with an error rather than generating an invalid certificate.
Can I generate a certificate from a CSR that contains Subject Alternative Names (SANs)?
Yes, mkcert fully supports CSRs containing Subject Alternative Names. The makeCertFromCSR function in cert.go extracts both DNS names and IP addresses from the CSR's SAN extension and includes them in the generated certificate template. This means you can create a CSR with multiple hostnames or IP addresses using OpenSSL, and mkcert will preserve all of them in the final certificate.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →