Minimal openssl.cnf

Summary: You need an openssl.cnf to issue certificates with OpenSSL. This post gives minimal working examples for typical test/demo cases.

Why is it needed?

OpenSSL commands (that is, the ones invoked from the command line) are mostly controlled by their options. But in order to issue X.509 certificates or CSRs OpenSSL needs a configuration file. This file may contain no useful information, but is still required. This post gives and explains minimal configuration files for OpenSSL commands used for certificate generation: x509, req and ca.

OpenSSL installation should supply a default configuration file, normally called openssl.cnf. Below, we'll use expressions openssl.cnf and "OpenSSL configuration file" interchangeably.

The topic of this post is the minimal configuration file. Sometimes the command will need more parameters than such minimum contains; in these cases they will be provided via command-line options. These options are kept at minimum too, so in real applications you'd likely need to pass more parameters - either via the config file or through the options.

Generate the private key

Generation of the private key can be included in some of the commands below, but for clarity let's create a private key with a separate command. To sound modern, pick an elliptic curve from openssl ecparam -list_curves with the name which sounds cute, such as secp521r1 (on a serious note - selection of the elliptic curve is out of scope of this post):

$ openssl ecparam -genkey -name secp521r1 -out privkey.pem

We'll use this same key for all certificates which appear later; of course such practice is acceptable only for demonstration purposes.

Create a self-signed CA certificate

This command needs a config file. Unless one is provided, OpenSSL will use the default, which may not contain what you want. There are two ways to provide a custom config:

  • -config option
  • OPENSSL_CONF environment variable

Below, we'll use the first way to show the config file in a more explicit manner.

Using "req -x509" command

The minimum config file for this command is:

[ req ]
distinguished_name = req_dn

[ req_dn ]

Call this file openssl-min-req.cnf. With it, you can issue self-signed certificates:

$ openssl req -new -x509 -nodes -key privkey.pem -config openssl-min-req.cnf -subj "/CN=My self-signed CA certificate" -out ca.pem

If we do not specify the version explicitly or request any of X.509v3 extensions, then OpenSSL sets the version the certificate to 1.

Check with openssl x509 -purpose -in ca.pem and observe that various "CA" purposes come with Yes (WARNING code=3).

Surprisingly, for a V3 certificate, there seems to be no clear indication whether it is a CA certificate or not. Two extensions claim properties related to CA functionality. OpenSSL's C API function X509_check_ca returns non-zero when the certificate either has CA:TRUE in basicConstraints extension, or keyCertSign in keyUsage extension. Other software may follow other rules (for example, require CA:TRUE). To satisfy OpenSSL's interpretation, the minimal openssl.cnf can be like this:

[ req ]
distinguished_name = req_dn
x509_extensions = v3_ext

[ req_dn ]

[ v3_ext ]
basicConstraints = CA:true

Using "ca -selfsign" command

Below is the minimal openssl-ca.cnf which would do the job.

[ ca ]
default_ca      = CA_default

[ CA_default ]
database        = index.txt
serial          = serial.txt
policy          = policy_default

[ policy_default ]

For the command to succeed, three files referenced above must be created:

$ touch index.txt index.txt.attr
$ echo '01' > serial.txt

When done, you can get your own self-signed CA certificate:

$ openssl ca -config openssl-ca.cnf -selfsign -in csr.pem -keyfile privkey.pem -md default -out ca.pem -outdir . -days 365 -batch

Create a certificate signed by your new CA

Create a CSR

A CSR (Certificate Signing Request) is made with req command. For it, the "minimum request openssl.cnf" is sufficient:

$ openssl req -new -config openssl-min-req.cnf -key privkey.pem -nodes -subj "/CN=Non-CA example certificate" -out csr.pem

Inspect the CSR with openssl req -text -noout -in csr.pem.

Having a CSR, the corresponding certificate can be issued using x509 or ca commands.

Sign the CSR using "x509 -req" command

$ openssl x509 -req -in csr.pem -CA ca.pem -CAkey privkey.pem -CAcreateserial -out cert.pem

The x509 command seems to have no option -config, but it honors the environment variable OPENSSL_CONF. If the file is not readable, OpenSSL prints

WARNING: can't open config file: /usr/lib/ssl/openssl.cnf

and continues. For the example above, config file is not needed; and if it is not needed, you should not use it, because it may bring in items which you do not want. It looks like the way to "disable" config file processing is to set OPENSSL_CONF=some_nonexisting_file.

Sign the CSR using "ca" command

Previously mentioned openssl-ca.cnf works also for this case, and cannot be reduced.

$ openssl ca -config openssl-ca.cnf -cert ca.pem -keyfile privkey.pem -in csr.pem -out cert.pem -outdir . -md default -days 365 -batch

By default the ca command does not copy the X.509v3 extensions from the CSR (the ones specified in x509_extensions section of the [ req ] part in our example openssl-min-req.cnf) to the signed certificate. To do so, add copy_extensions = copy line to the CA section ([ CA_default ] in our example openssl-ca.cnf). Alternatively, the CA may add own extensions when signing a CSR - for example, set CA:FALSE. These should be listed in the section with the name given by the variable x509_extensions in the [ CA_default ] section.

Conclusion

  • To issue certificates with OpenSSL, a configuration file is needed.
  • OpenSSL will use the default config file unless you provide another one via command-line option or an environment variable.
    • Except that x509 -req is missing the option.
  • While the default may work for some cases, if you need any control over your certificate, you'll need to create the config file.
  • You get more control over the content of your certificates when starting with the bare minimum than with the default. The minimal examples are provided in this post.

Contents © 2018 Konstantin Shemyak - Powered by Nikola