Obtain an elliptic curve certificate from Let's Encrypt

You can ask Let’s Encrypt to sign a certificate by sending the Certificate Signing Request (CSR). In Public Key Infrastructure (PKI) systems, a CSR is a message sent from an applicant to a Certificate Authority (CA) in order to apply for a digital identity certificate. It usually contains the Common Name (CN), the country, the e-mail address, the public key for which the certificate should be issued and much more. Concerning the common name it should be the fully qualified domain name (FQDN) of your server. It must match exactly what you type in your web browser or you will receive a name mismatch error.

In this article, we will generate a private key using Elliptic Curve Digital Signature Algorithm (ECDSA) with the NIST P-384 (secp384r1) curve.

Information and requirements

These elements are to be taken into consideration to follow this article:

Preliminary

Create directories.

sudo mkdir -p /etc/pki/tls/private/domain.fr/
sudo mkdir -p /etc/pki/tls/certs/domain.fr/

Generate the private key

sudo openssl ecparam -check -name secp384r1 -genkey -noout -out /etc/pki/tls/private/domain.fr/privkey.pem -rand /dev/urandom

Set the correction permission

sudo chmod 440 /etc/pki/tls/private/domain.fr/privkey.pem

Flags explanation:

Verify that OpenSSL do things correctly

sudo openssl ec -in /etc/pki/tls/private/domain.fr/privkey.pem -noout -text
read EC key
Private-Key: (384 bit)
priv:
    <hidden>
pub:
    <hidden>
ASN1 OID: secp384r1
NIST CURVE: P-384

Flags explanation:

We can see that the curve is the good one (P-384).

Create the OpenSSL configuration for the certificate

Next, we must create an OpenSSL configuration file with parameters specific to the domain for which we wish to obtain a TLS certificate. Copy the following content into /etc/openssl.cnf and modify it to fit your needs.

[ req ]
prompt = no
encrypt_key = no
default_md = sha512
distinguished_name = dname
req_extensions = reqext

[ dname ]
CN = domain.fr
emailAddress = contact@domain.fr

[ reqext ]
subjectAltName = DNS:domain.fr, DNS:*.domain.fr

The [ req ] section contains:

The [ dname ] section contains:

The [ reqext ] section contains:

If you don’t want a wildcard certificate remove , DNS: *.domain.fr in subjectAltName.

Create a CSR

The final client-side step is to generate the CSR, that we will then pass to Let’s Encrypt to sign, and return to us the signed certificate.

sudo openssl req -utf8 -new -key /etc/pki/tls/private/domain.fr/privkey.pem -out /etc/pki/tls/certs/domain.fr/csr.pem -config /etc/openssl.cnf -rand /dev/urandom

Flags explanation:

Verify that OpenSSL do things correctly

openssl req -in /etc/pki/tls/certs/domain.fr/csr.pem -noout -text -verify
verify OK
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: CN = domain.fr, emailAddress = contact@domain.fr
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    <hidden>
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        Attributes:
        Requested Extensions:
            X509v3 Subject Alternative Name:
                DNS:domain.fr
    Signature Algorithm: ecdsa-with-SHA512
         <hidden>

Flags explanation:

Ask Let’s Encrypt to sign the certificate

The last step is to pass the CSR to Let’s Encrypt with an Automatic Certificate Management Environment (ACME) client. Here, we will use certbot. We will consider that the domain is registered with OVH. We can use the corresponding plugin to handle verification, which is extremely convenient, requiring no manual intervention in the process. If you use another DNS provider, you can read the documentation here.

Install required utilities

sudo dnf -y install epel-release
sudo dnf -y install certbot python3-certbot-dns-ovh

Creating API keys

The ACME client must access to the OVH account to perform DNS modifications. To do this, you have to create API keys here. Fill-in the fields as follow:

By clicking on Create keys, if your multi-factor authentication is enabled (I hope to), you’ll receive the OTP code. Once authenticated, 5 fields will appear, 3 are important: Application Key, Application Secret and Consumer Key.

Copy the following content into /etc/.ovh.ini.

dns_ovh_endpoint = ovh-eu
dns_ovh_application_key = <application_key>
dns_ovh_application_secret = <application_secret>
dns_ovh_consumer_key = <consumer_key>

Then, set the correct permission.

sudo chmod 600 /etc/.ovh.ini

Send the request

It is generally advisable to do a --dry-run first to make sure everything is in order.

sudo certbot certonly --dry-run --dns-ovh --dns-ovh-credentials /etc/.ovh.ini --domain "domain.fr" --domain "*.domain.fr" --csr /etc/pki/tls/certs/domain.fr/csr.pem
[...]

IMPORTANT NOTES:
 - The dry run was successful.

If you don’t want a wildcard certificate, remove --domain "*.domain.fr". The SANs you specify in subjectAltName must match in text and number with what you specify via the --domain flag.

The flag --csr /etc/pki/tls/certs/domain.fr/csr.pem tells certbot that we already have a certificate that we just need Let’s Encrypt to sign for us.

The certbot client will check that the list of domains requested on the command line matches the domains listed in the certificate.It will use the OVH DNS plugin to verify the ownership of the domain, and let us know if anything is wrong. If nothing is wrong, it will tell you: The dry run was successful like right here.

If everything is good, you can ask for the signature of your certificate for real.

sudo certbot certonly --dns-ovh --dns-ovh-credentials /etc/.ovh.ini --domain "domain.fr" --domain "*.domain.fr" --csr /etc/pki/tls/certs/domain.fr/csr.pem

After a delay, the client will produce 3 files:

At this point, the CSR can be deleted.

sudo rm -f /etc/pki/tls/certs/domain.fr/csr.pem

You can inspect the certificates returned by the client with OpenSSL using the x509 command.

openssl x509 -in 0001_chain.pem -noout -text

Flags explanation:

Move certificates and key

sudo mv 0000_cert.pem /etc/pki/tls/certs/domain.fr/cert.pem
sudo mv 0000_chain.pem /etc/pki/tls/certs/domain.fr/chain.pem
sudo mv 0001_chain.pem /etc/pki/tls/certs/domain.fr/fullchain.pem

Set correction permissions

sudo chmod 444 /etc/pki/tls/certs/domain.fr/*.pem

Restore SELinux context

sudo restorecon -v /etc/pki/tls/certs/domain.fr/cert.pem
sudo restorecon -v /etc/pki/tls/certs/domain.fr/fullchain.pem
sudo restorecon -v /etc/pki/tls/certs/domain.fr/chain.pem