We have discussed in depth about certificates generation and renewal in our previous articles. But there can also be a situation when the root CA used to sign the server and client certificates, itself expires. So in such scenarios we must renew the expired CA certificate to be able to use it with all the signed certificates.
I have created a directory /certs
on ca-server.example.com
where I will be storing the certificates.
Before we actually renew the root CA certificate, I will create a setup with a root CA certificate and server certificates. Then we will intentionally expire our root CA certificate and generate a new CA certificate using the existing root CA key. Technically a root CA certificate cannot be renewed once expired. We can only generate a new CA certificate but when created using the existing key, it can be used to sign existing server certificates.
Generate Root CA private key
First we need a root CA certificate for our demonstration. To generate a root CA certificate, we would need a private key:
[root@ca-server certs]# openssl genrsa -out orig-ca.key 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
.........++++
....................................................++++
e is 65537 (0x010001)
Generate Root CA Certificate
We will use this private key to generate a root CA certificate with a validity of 1 year (365 days).
[root@ca-server certs]# openssl req -new -x509 -days 365 -key orig-ca.key -out orig-cacert.pem
Output snippet from my node:
Verify the validity of the root CA certificate
[root@ca-server certs]# openssl x509 -noout -text -in orig-cacert.pem | grep -i -A2 validity
Validity
Not Before: Mar 19 09:28:10 2021 GMT
Not After : Mar 19 09:28:10 2022 GMT
So currently we have these two certificate files:
[root@ca-server certs]# ls -l total 8 -rw-r--r-- 1 root root 2191 Mar 19 14:58 orig-cacert.pem -rw------- 1 root root 3243 Mar 19 14:57 orig-ca.key
Create server certificate
Next we will create a server certificate which we will use with our apache server on server.example.com
so it is important that we use the same hostname as Common Name or else the TCP handshake will fail.
Generate private key
Again for a server certificate we would need a private key:
[root@ca-server certs]# openssl genrsa -out server.key 4096
Generating RSA private key, 4096 bit long modulus (2 primes)
.....................................................++++
............++++
e is 65537 (0x010001)
Generate Certificate Signing Request
Next we will generate a Certificate Signing Request (CSR) using the private key. Here make sure you give the Common Name of your server. You can also create a SAN certificate with multiple DNS and IP entries.
[root@ca-server certs]# openssl req -new -key server.key -out server.csr
Output snippet from my node:
Generate server certificate
Now we will sign and generate our server certificate using the CSR, root CA private key along with the root CA certificate. Here we have intentionally given the expiry of server certificate as 10 years which is much higher then the CA certificate expiry. So the CA certificate will be expired before the server certificate.
[root@ca-server certs]# openssl x509 -req -days 3650 -in server.csr -CA orig-cacert.pem -CAkey orig-ca.key -CAcreateserial -out server.crt
Signature ok
subject=C = IN, ST = Karnataka, L = Bengaluru, O = GoLinuxCloud, OU = R&D, CN = server.example.com, emailAddress = admin@golinuxcloud.com
Getting CA Private Key
Following are the list of certificates created till this stage:
[root@ca-server certs]# ls -l
Output snippet from my node:
Verify the server certificate
We can use the CA certificate which we had used to sign the server certificate, to verify it's authenticity:
[root@ca-server certs]# openssl verify -CAfile orig-cacert.pem -verbose server.crt
server.crt: OK
Forcefully expire the root CA certificate
Since we know that our CA certificate is valid only for 1 year so I will just change the date of my localhost node
[root@ca-server certs]# date
Fri Mar 19 14:59:38 IST 2021
I have changed the date to one year later on my localhost here:
[root@ca-server certs]# date --set "19 Mar 2022 14:59:00"
Sat Mar 19 14:59:00 IST 2022
Since openssl will use the date and time of localhost to verify the validity of the certificate, it will now report the CA certificate as expired.
[root@ca-server certs]# openssl verify -CAfile orig-cacert.pem -verbose server.crt
C = IN, ST = Karnataka, L = Bengaluru, O = GoLinuxCloud, OU = R&D, CN = ca-server.example.com, emailAddress = admin@golinuxcloud.com
error 10 at 1 depth lookup: certificate has expired
error server.crt: verification failed
Renew root CA certificate
Next we will create a new CA certificate using the existing root private key. The openssl x509
command processes an X.509 certificate. In this case, the command converts an X.509 certificate to a certificate request (-x509toreq
).
[root@ca-server certs]# openssl x509 -x509toreq -in orig-cacert.pem -signkey orig-ca.key -out new-server.csr
Getting request Private Key
Generating certificate request
Next we will use the CSR generated from the last step to create a new CA certificate. We have given expiry of 1 year for this new CA certificate.
[root@ca-server certs]# openssl x509 -req -days 365 -in new-server.csr -signkey orig-ca.key -out new-cacert.pem Signature ok subject=C = IN, ST = Karnataka, L = Bengaluru, O = GoLinuxCloud, OU = R&D, CN = ca-server.example.com, emailAddress = admin@golinuxcloud.com Getting Private key
Verify server certificate using the new root CA
Now let us verify the server certificate with this new CA certificate which we signed using old CA certificate earlier:
[root@ca-server certs]# openssl verify -CAfile new-cacert.pem -verbose server.crt
server.crt: OK
So the certificate reports valid for the new root CA certificate, even thought the sha256sum of both these certificates are different:
[root@ca-server certs]# sha256sum orig-cacert.pem bc15090325afbe8daec8fad8c9ed0273b5b21cea84738a9372f0a07b1bdaa55b orig-cacert.pem [root@ca-server certs]# sha256sum new-cacert.pem a3562877906667b3a8d934f1860b81c109fbed9b44db72ac32e646644b106fc3 new-cacert.pem
Actually we can verify the signature of both these root CA signatures:
[root@ca-server certs]# openssl x509 -noout -text -in orig-cacert.pem ... RSA Public-Key: (4096 bit) Modulus: 00:cc:c9:fb:12:c1:91:ee:8f:12:84:06:ad:72:e1: b8:24:b1:9a:b7:d7:1b:ed:93:26:e5:73:88:36:cb: 69:39:77:2f:6f:9e:47:94:67:a8:51:02:b6:cf:c2: 7f:a0:29:82:c0:73:78:a0:d7:6d:f6:ef:88:c7:41: 68:c0:db:69:39:11:de:4b:87:56:b5:d7:14:1f:6a: dd:1d:ca:a4:86:fd:d7:2f:71:71:11:ec:7d:6e:2c: 91:d9:13:f4:16:aa:54:16:ad:01:b3:df:77:5f:21: 24:48:b7:5d:70:73:0d:7d:dc:48:8a:a5:09:2b:f3: 8f:fd:d2:13:42:4f:bd:06:54:50:ac:ac:a6:a0:02: 6e:9b:f6:0e:0e:31:f1:cd:40:4b:b1:4c:9c:fa:f8: ce:39:df:ed:e4:f0:b2:aa:1e:e5:f8:75:af:d7:e1: 54:86:53:d7:af:6b:62:b7:a0:ee:d5:2f:eb:a9:e3: 6c:2b:68:4a:15:a5:f2:eb:a2:98:cc:4b:87:87:92: 44:62:a1:5e:b7:88:97:47:ba:2f:11:55:db:02:3d: 40:c9:55:7c:4b:ae:c9:5d:07:aa:c1:49:08:37:1f: a7:17:0d:20:a4:bd:86:53:13:5a:fa:d2:57:84:56: 98:c1:bd:ad:72:01:6d:fc:6e:12:f4:77:d7:0e:93: 78:8c:32:75:5b:17:6f:79:92:d3:18:1d:d0:c3:b4: 2e:f8:31:ce:26:1f:fb:09:ab:cb:f7:fe:f2:1b:7e: 9f:bd:91:07:32:ca:b5:47:24:e0:65:18:80:fe:32: 11:50:64:4c:15:07:42:05:6b:05:2d:41:53:ad:25: 9e:be:b3:ab:88:dd:14:b6:71:33:3a:53:d4:68:45: 09:54:91 Exponent: 65537 (0x10001) ... [root@ca-server certs]# openssl x509 -noout -text -in new-cacert.pem ... Public Key Algorithm: rsaEncryption RSA Public-Key: (4096 bit) Modulus: 00:cc:c9:fb:12:c1:91:ee:8f:12:84:06:ad:72:e1: b8:24:b1:9a:b7:d7:1b:ed:93:26:e5:73:88:36:cb: 69:39:77:2f:6f:9e:47:94:67:a8:51:02:b6:cf:c2: 7f:a0:29:82:c0:73:78:a0:d7:6d:f6:ef:88:c7:41: 68:c0:db:69:39:11:de:4b:87:56:b5:d7:14:1f:6a: dd:1d:ca:a4:86:fd:d7:2f:71:71:11:ec:7d:6e:2c: 91:d9:13:f4:16:aa:54:16:ad:01:b3:df:77:5f:21: 24:48:b7:5d:70:73:0d:7d:dc:48:8a:a5:09:2b:f3: 8f:fd:d2:13:42:4f:bd:06:54:50:ac:ac:a6:a0:02: 6e:9b:f6:0e:0e:31:f1:cd:40:4b:b1:4c:9c:fa:f8: ce:39:df:ed:e4:f0:b2:aa:1e:e5:f8:75:af:d7:e1: 54:86:53:d7:af:6b:62:b7:a0:ee:d5:2f:eb:a9:e3: 6c:2b:68:4a:15:a5:f2:eb:a2:98:cc:4b:87:87:92: 44:62:a1:5e:b7:88:97:47:ba:2f:11:55:db:02:3d: 40:c9:55:7c:4b:ae:c9:5d:07:aa:c1:49:08:37:1f: a7:17:0d:20:a4:bd:86:53:13:5a:fa:d2:57:84:56: 98:c1:bd:ad:72:01:6d:fc:6e:12:f4:77:d7:0e:93: 78:8c:32:75:5b:17:6f:79:92:d3:18:1d:d0:c3:b4: 2e:f8:31:ce:26:1f:fb:09:ab:cb:f7:fe:f2:1b:7e: 9f:bd:91:07:32:ca:b5:47:24:e0:65:18:80:fe:32: 11:50:64:4c:15:07:42:05:6b:05:2d:41:53:ad:25: 9e:be:b3:ab:88:dd:14:b6:71:33:3a:53:d4:68:45: 09:54:91 Exponent: 65537 (0x10001) ...
As you can see, the signature of both the CA certificates are the same.
Summary
In this tutorial we learned about renewal of expired root CA certificates. It is normally a good idea to define a larger period such as 10 years for a CA certificate to avoid such scenarios. This can be a problem mostly in intranet where we locally generate our own CA and server or client certificates. You can't "renew" a root cert. All you can do is generate a new one. It is recommended to generate a new root CA certificate at least a year or two before your old one expires so you have time to change over without being against a time wall if something goes wrong. That way you can always temporarily switch back to the old certs until you get your problems with the new one resolved.
Very good article
This seemed like the most helpful tutorial for my issue, but after trying quite a few things, on another website I ran across:
Where ca.crt is your expired cert, ca_new.crt will be your new 10 year ca cert, and ca.key is your existing key. That was all I needed.
Thank you so much! All the guides, including the one here, talked about using x509toreq, but it never included the CA:TRUE flag in the resulting (new) certificates, and verify operations of old server certificates against the new CA certificate would fail. There does not seem to be a straight forward way to copy the extensions from a x509 certificate to an OpenSSL .cnf file either, I would have had to type them off manually.
Your command – a single (sic!) line – it worked immediately, it returned a renewed root certificate which contained all the previous extensions and which old server certificates would verify against as if nothing ever happened.
Thank you!!
Hi, thank you for this helpful post. Can you tell me how to renew a certificate that contains extensions like various alternative subject names? Because the x509toreq command does not copy them by default and simply providing the extfile that I used to create the certificate using the -extfile options does not work either for me.
Regards,
Tobias
I am sorry but I have never used SAN in a rootCA certificate.
You are trying to renew a server/client certificate or a rootCA certificate?
Can you give some more insights to your scenario so I can understand the root cause
Ah, yes, I should have told you. I try to renew a server certificate.
renewing a server/client certificate should be same as generating a new one, instead we use existing private key.
let me write one detailed article with the steps to retain all x.509 extensions (including SAN)
The article should be ready by tomorrow
Here you go:
https://www.golinuxcloud.com/renew-ssl-tls-server-certificate-openssl/