Certificate private key: how to generate and protect it

9 min readUpdated

A private key is the secret half of the key pair behind an SSL certificate. When you generate a certificate key, you create both halves at once; the certificate is issued later, for the public half. Each of the HTTPS certificates a server presents carries one public key, and the certificate binds that key to your name so that clients can be confident the matching private key is yours [1]. The certificate is public and goes to every client that connects; the private key stays on the server, in a file with restricted access [6].

What it is
the secret half of a key pair; the public half is in the certificate [1]
File format
PKCS #8 structure, written as PEM text by OpenSSL unless told otherwise [2][5]
Generate it
with openssl genpkey [5], on the machine that will use it
Access
a file with restricted access that the server process can still read [6]
After a leak
revoke, stop using it, and replace both the key and the certificate [7]

What a private key file contains

RFC 5958, which replaced the PKCS #8 of RFC 5208, defines the syntax for private-key information: a version, an algorithm identifier, the private key, optional attributes and, in its second version, an optional public key [2]. OpenSSL normally writes this PKCS #8 form and uses an older "traditional" format only when asked [5].

An RSA private key as defined in RFC 8017 includes the modulus and the public exponent alongside the private exponent and the primes [3]. For elliptic-curve keys, RFC 5915 makes the public key field optional and says implementations SHOULD always include it [4]. So an RSA key file always carries the public half of the key pair, and an EC key file does whenever it follows that SHOULD. In our run, openssl pkey -text_pub printed Public-Key: (256 bit) for an EC key and Public-Key: (2048 bit) with Exponent: 65537 for an RSA key [8].

That is how a certificate and its key are compared: the public key derived from the key file must equal the one in the certificate, as the certificate and key matcher in the tools section shows. A certificate cannot replace a lost key file, because it carries only the public key [1].

How to generate a certificate key with OpenSSL

On the manual route of generating an SSL certificate, the key comes first: make it on the server that will use it, then build the request from it. openssl genpkey is the command the OpenSSL manual encourages over the algorithm-specific utilities [5]:

$ openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out example.com.key
$ openssl pkey -in example.com.key -noout -check
Key is valid
  • -algorithm EC with ec_paramgen_curve:P-256 creates an elliptic-curve key on P-256, the kind an ECDSA certificate uses. For RSA, use -algorithm RSA -pkeyopt rsa_keygen_bits:2048; 2048 bits is also the default size [5].

  • -check checks that the private and public components of the key pair are consistent [5].

  • The file is PEM unless you add -outform DER [5].

In our run the key file came out as -rw-------, readable only by its owner, while a public key and a signing request written from it in the same directory followed the shell's umask as -rw-rw-r-- [8].

Next, openssl req -new -key example.com.key builds the request from this key instead of creating a new one [5]; the fields it needs are in how to create a certificate signing request. In our run the public key in that request was identical to the one derived from the key file [8].

Generating a key and a certificate

An SSL key and certificate are two different things, made in two places. You generate the key on the server that will use it; a certificate authority issues the certificate, for the public half of that key [1] [7]. Creating an SSL key and certificate for a site therefore takes three steps:

  1. Generate the private key with openssl genpkey, as above.

  2. Build the signing request from that key. The key signs the request and the matching public key is placed in it [5]; the fields are in how to create a certificate signing request.

  3. Send the request to the authority. The certificate it issues binds that public key to the subject named in it [1].

The authority cannot do the first step for you: for website certificates the Baseline Requirements forbid it to generate the key pair on your behalf [7]. The request carries the public key, not the key file [5]. The certificate is the public file that goes to every client, and the key file stays on the server [6].

Where the private key lives

Where the key lives depends on who terminates TLS for the site, and so does who generates it.

Where the private key is kept and who generates it
SetupWhere the key isWho generates it
Your own servera file named in the server configuration, such as ssl_certificate_key in nginx; it may share one file with the certificate [6]you, with OpenSSL
ACME client on your servera file the client keeps on that serverthe client, or you: Certbot, for example, does not reuse the key at renewal unless --reuse-key is set, and with --csr it uses a certificate signing request you created [9]
Hosting platform or CDNwith the platform that terminates HTTPSthe platform
Online generatorthe generator's server, or your browser if it creates the key therethe site that runs it

The key does not have to be a file: nginx can load it by id through an OpenSSL provider URI scheme such as pkcs11 [6].

A certificate from a free certificate authority arrives through ACME, so on the client route the key stays with the ACME client on your server. SSL certificate authorities are not where the key comes from: for website certificates they may not generate the key pair for you, and may not accept a request for a key they generated [7].

On Bridge CDN the hosting platform row applies: the key pair behind the certificate belongs to the platform, Bridge SSL is its certificate layer, and there is no certificate upload.

How to protect a private key

Protecting a private key means controlling who can read the file, and limiting what a copy is worth, so that a lost file does not turn into a key compromise.

  • Restrict the file. nginx describes the private key as a secure entity, to be stored in a file with restricted access that its master process can still read; if the key shares a file with the certificate, that file needs the same restriction [6]. Check the file permissions again after you copy or move the key.

  • Encrypt the copies that travel. openssl pkey -aes-256-cbc writes the key encrypted under a passphrase, and the PEM header line then marks the key as encrypted [5][8]. RFC 5958 says the encryption must be as strong as the key it protects [2]. With a wrong passphrase, OpenSSL stopped with Could not read key from example.com.enc.key [8].

  • Decide how the server unlocks it. nginx loads an encrypted key with passphrases from a file named by ssl_password_file, trying them in turn [6], so the passphrase then sits on the same machine as the key.

  • Treat it as an obligation. With a publicly trusted certificate, the subscriber agreement commits you to take all reasonable measures to keep the private key confidential and under your control [7].

When a key counts as compromised

The Baseline Requirements call a private key compromised when its value has been disclosed to an unauthorized person, or an unauthorized person has had access to it [7]. Access is enough; nobody has to have used the key. RFC 5280 names the stakes: failing to protect a private key lets an attacker masquerade as its owner [1].

A key can also be weak from the start. An authority must reject a request when there is clear evidence that the method used to generate the key was flawed, and when the public key corresponds to a known weak private key, naming the Debian, ROCA and Close Primes vulnerabilities [7].

Once a key may have leaked:

  1. Request revocation of every certificate that uses it, with key compromise as the reason; revoking a certificate explains how to send the request and why revocation comes first here.

  2. Stop using the key and its certificates, as the subscriber agreement requires [7].

  3. Generate a new key, not only a new request. An authority notified of the compromise must reject new requests for that key, and one that learns the key reached an unauthorized person must revoke every certificate that includes its public key [7].

  4. Get a certificate for the new key and check the pair before reloading.

FAQ

What is a private key?

The secret half of a key pair. For an SSL certificate, the certificate publishes the public key and the server keeps the private key; clients rely on the certificate to know that the private key belongs to the name in it. Disclosure of the private key can let someone else masquerade as you. [1][2]

How do I generate a private key for an SSL certificate?

Run openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out example.com.key on the server that will use it, or -algorithm RSA -pkeyopt rsa_keygen_bits:2048 for an RSA key. Then build the signing request from it with openssl req -new -key example.com.key. [5]

Does the certificate authority generate my private key?

No. For website certificates, the Baseline Requirements forbid the authority to generate the key pair for you or to accept a request for a key it generated earlier. [7]

Sources

  1. RFC 5280, Internet X.509 Public Key Infrastructure Certificate and CRL Profile: §3.1, §4.1.2.7, §8.

  2. RFC 5958, Asymmetric Key Packages: §1, §2, §3, §6; obsoletes RFC 5208 (PKCS #8 v1.2).

  3. RFC 8017, PKCS #1: RSA Cryptography Specifications Version 2.2: Appendix A.1.2.

  4. RFC 5915, Elliptic Curve Private Key Structure: §3.

  5. OpenSSL 3.0 manual: openssl-genpkey, openssl-pkey, openssl-req.

  6. nginx documentation: Configuring HTTPS servers; ngx_http_ssl_module, directives ssl_certificate_key and ssl_password_file.

  7. CA/Browser Forum Baseline Requirements, version 2.3.1: §1.6.1, §6.1.1.3, §6.1.2, §9.6.3.

  8. Lab runs for this page: OpenSSL 3.0.13 on Linux Mint 22.1, test name example.com.

  9. Certbot user guide: command-line options --reuse-key, --no-reuse-key, --csr.