136

In 2004, I set up a small certification authority using OpenSSL on Linux and the simple management scripts provided with OpenVPN. In accordance with the guides I found at the time, I set the validity period for the root CA certificate to 10 years. Since then, I have signed many certificates for OpenVPN tunnels, web sites and e-mail servers, all of which also have a validity period of 10 years (this may have been wrong, but I didn't know better at the time).

I have found many guides about setting up a CA, but only very little information about its management, and in particular, about what has to be done when the root CA certificate expires, which will happen some time in 2014. So I have the following questions:

  • Will the certificates that have a validity period extending after the expiry of the root CA certificate become invalid as soon as the latter expires, or will they continue to be valid (because they were signed during the validity period of the CA certificate)?
  • What operations are needed to renew the root CA certificate and ensure a smooth transition over its expiry?
    • Can I somehow re-sign the current root CA certificate with a different validity period, and upload the newly-signed cert to clients so that client certificates remain valid?
    • Or do I need to replace all client certificates with new ones signed by a new root CA certificate?
  • When should the root CA certificate be renewed? Close to expiry, or a reasonable time before expiry?
  • If the renewal of the root CA certificate becomes a major piece of work, what can I do better now to ensure a smoother transition at the next renewal (short of setting the validity period to 100 years, of course)?

The situation is made slightly more complicated by the fact that my only access to some of the clients is through an OpenVPN tunnel that uses a certificate signed by the current CA certificate, so if I have to replace all client certs, I will need to copy the new files to the client, restart the tunnel, cross my fingers and hope that it comes up afterwards.

7 Answers 7

190
+100

Keeping the same private key on your root CA allows for all certificates to continue to validate successfully against the new root; all that's required of you is to trust the new root.

The certificate signing relationship is based on a signature from the private key; keeping the same private key (and, implicitly, the same public key) while generating a new public certificate, with a new validity period and any other new attributes changed as needed, keeps the trust relationship in place. CRLs, too, can continue over from the old cert to the new, as they are, like certificates, signed by the private key.


So, let's verify!

Make a root CA:

openssl req -new -x509 -keyout root.key -out origroot.pem -days 3650 -nodes

Generate a child certificate from it:

openssl genrsa -out cert.key 1024
openssl req -new -key cert.key -out cert.csr

Sign the child cert:

openssl x509 -req -in cert.csr -CA origroot.pem -CAkey root.key -create_serial -out cert.pem
rm cert.csr

All set there, normal certificate relationship. Let's verify the trust:

# openssl verify -CAfile origroot.pem -verbose cert.pem
cert.pem: OK

Ok, so, now let's say 10 years passed. Let's generate a new public certificate from the same root private key.

openssl req -new -key root.key -out newcsr.csr
openssl x509 -req -days 3650 -in newcsr.csr -signkey root.key -out newroot.pem
rm newcsr.csr

And.. did it work?

# openssl verify -CAfile newroot.pem -verbose cert.pem
cert.pem: OK

But.. why? They're different files, right?

# sha1sum newroot.pem
62577e00309e5eacf210d0538cd79c3cdc834020  newroot.pem
# sha1sum origroot.pem
c1d65a6cdfa6fc0e0a800be5edd3ab3b603e1899  origroot.pem

Yes, but, that doesn't mean that the new public key doesn't cryptographically match the signature on the certificate. Different serial numbers, same modulus:

# openssl x509 -noout -text -in origroot.pem
        Serial Number:
            c0:67:16:c0:8a:6b:59:1d
...
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:bd:56:b5:26:06:c1:f6:4c:f4:7c:14:2c:0d:dd:
                    3c:eb:8f:0a:c0:9d:d8:b4:8c:b5:d9:c7:87:4e:25:
                    8f:7c:92:4d:8f:b3:cc:e9:56:8d:db:f7:fd:d3:57:
                    1f:17:13:25:e7:3f:79:68:9f:b5:20:c9:ef:2f:3d:
                    4b:8d:23:fe:52:98:15:53:3a:91:e1:14:05:a7:7a:
                    9b:20:a9:b2:98:6e:67:36:04:dd:a6:cb:6c:3e:23:
                    6b:73:5b:f1:dd:9e:70:2b:f7:6e:bd:dc:d1:39:98:
                    1f:84:2a:ca:6c:ad:99:8a:fa:05:41:68:f8:e4:10:
                    d7:a3:66:0a:45:bd:0e:cd:9d
# openssl x509 -noout -text -in newroot.pem
        Serial Number:
            9a:a4:7b:e9:2b:0e:2c:32
...
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:bd:56:b5:26:06:c1:f6:4c:f4:7c:14:2c:0d:dd:
                    3c:eb:8f:0a:c0:9d:d8:b4:8c:b5:d9:c7:87:4e:25:
                    8f:7c:92:4d:8f:b3:cc:e9:56:8d:db:f7:fd:d3:57:
                    1f:17:13:25:e7:3f:79:68:9f:b5:20:c9:ef:2f:3d:
                    4b:8d:23:fe:52:98:15:53:3a:91:e1:14:05:a7:7a:
                    9b:20:a9:b2:98:6e:67:36:04:dd:a6:cb:6c:3e:23:
                    6b:73:5b:f1:dd:9e:70:2b:f7:6e:bd:dc:d1:39:98:
                    1f:84:2a:ca:6c:ad:99:8a:fa:05:41:68:f8:e4:10:
                    d7:a3:66:0a:45:bd:0e:cd:9d

Let's go a little further to verify that it's working in real world certificate validation.

Fire up an Apache instance, and let's give it a go (debian file structure, adjust as needed):

# cp cert.pem /etc/ssl/certs/
# cp origroot.pem /etc/ssl/certs/
# cp newroot.pem /etc/ssl/certs/
# cp cert.key /etc/ssl/private/

We'll set these directives on a VirtualHost listening on 443 - remember, the newroot.pem root certificate didn't even exist when cert.pem was generated and signed.

SSLEngine on
SSLCertificateFile /etc/ssl/certs/cert.pem
SSLCertificateKeyFile /etc/ssl/private/cert.key
SSLCertificateChainFile /etc/ssl/certs/newroot.pem

Let's check out how openssl sees it:

# openssl s_client -showcerts -CAfile newroot.pem -connect localhost:443

Certificate chain
 0 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=server.lan
   i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
 1 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
   i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
MIICHzCCAYgCCQCapHvpKw4sMjANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJB
...
-----END CERTIFICATE-----
(this should match the actual contents of newroot.pem)
...
Verify return code: 0 (ok)

Ok, and how about a browser using MS's crypto API? Gotta trust the root, first, then it's all good, with the new root's serial number:

newroot

And, we should still be working with the old root, too. Switch Apache's config around:

SSLEngine on
SSLCertificateFile /etc/ssl/certs/cert.pem
SSLCertificateKeyFile /etc/ssl/private/cert.key
SSLCertificateChainFile /etc/ssl/certs/origroot.pem

Do a full restart on Apache, a reload won't switch the certs properly.

# openssl s_client -showcerts -CAfile origroot.pem -connect localhost:443

Certificate chain
 0 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=server.lan
   i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
 1 s:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
   i:/C=AU/ST=Some-State/O=Internet Widgits Pty Ltd/CN=root
-----BEGIN CERTIFICATE-----
MIIC3jCCAkegAwIBAgIJAMBnFsCKa1kdMA0GCSqGSIb3DQEBBQUAMFQxCzAJBgNV
...
-----END CERTIFICATE-----
(this should match the actual contents of origroot.pem)
...
Verify return code: 0 (ok)

And, with the MS crypto API browser, Apache's presenting the old root, but the new root's still in the computer's trusted root store. It'll automatically find it and validate the cert against the trusted (new) root, despite Apache presenting a different chain (the old root). After stripping the new root from trusted roots and adding the original root cert, all is well:

oldroot


So, that's it! Keep the same private key when you renew, swap in the new trusted root, and it pretty much all just works. Good luck!

12
  • 5
    Anyways, what's the point of creating a new root certificate if you're just going to reuse the same private key? If you keep doing this over and over, then what's the point of even having an expiration date for the certificate? I thought the root expiration was used to force admins to make a newer (most likely stronger) private key that is more secure against the ever advancing machines trying to break the keys. A 40 bit key made 20 years ago is not secure enough for
    – jvhashe
    Aug 22, 2013 at 19:00
  • 3
    @jvhashe If the root certificate's no longer cryptographically strong enough, then you should be getting rid of it regardless of its expiration date. If you're generating your own root, there's nothing stopping you from setting it to expire hundreds of years past when you'll no longer be on the planet. Expiration is barely relevant on a root certificate - and for a child certificate, the expiration isn't really about cryptographic strength either (ask the CAs who are prepping to revoke all 1024-bit certs in October) - see here for more info. Aug 23, 2013 at 1:19
  • 3
    In addition to the above, I found that the serial number needs to be the same for this method to work. Aug 25, 2014 at 14:44
  • 3
    -set_serial 01 - WTF??? YOU CANNOT REUSE SERIAL NUMBERS. Did you even consult RFC 4158, Internet X.509 Public Key Infrastructure: Certification Path Building? Or are you just making it up as you go along? You have no idea of the problems you are causing in user agents when they start path building.
    – user145545
    Nov 10, 2016 at 18:09
  • 1
    @jww Did you read the answer? That's just a demonstration of the fact that the cryptography works. That command is literally just generating a test cert that we can verify against later, for the purposes of testing the relationship between the old and new root cert. If someone is using those commands directly, I certainly hope something breaks, and they realize that they need to pay attention to the context of something before blindly running it (or flying off the handle about whether 01 is an acceptable serial in a lab). Nov 10, 2016 at 18:18
21

I've noticed that CA extensions could be missing in the renewed certificate of the original CA key. This worked more appropriately for me (it creates a ./renewedselfsignedca.conf where v3 CA extensions are defined, and ca.key and ca.crt are assumed to be the original CA key and certificate):

openssl x509 -x509toreq -in ca.crt -signkey ca.key -out \
    renewedselfsignedca.csr

echo -e "[ v3_ca ]\nbasicConstraints= CA:TRUE\nsubjectKeyIdentifier=
hash\nauthorityKeyIdentifier= keyid:always,issuer:always\n" > \
    renewedselfsignedca.conf

openssl x509 -req -days 1095 -in renewedselfsignedca.csr -signkey \
    ca.key -out renewedselfsignedca.crt \
    -extfile ./renewedselfsignedca.conf \
    -extensions v3_ca
5
  • 2
    This has been an extremely helpful addition. The actually valid answer doesn't result in a sufficiently compatible certificate for me if you have arbitrary settings on your original root ca.
    – Theuni
    Dec 2, 2014 at 17:06
  • 1
    Seconded, very helpful. Another addition: like Scott Presnell in the comments to the accepted answer, I also had to manually specify the hexadecimal serial number of the renewed certificate so that it matched the old one. This meant adding -set_serial 0xdeadbeefabba (not the real serial no :) ) to the latter x509 command. Only then did my client certificates successfully verify against the renewed CA certificate.
    – JK Laiho
    May 19, 2015 at 13:27
  • This method is easier as it keeps the same information than the previous certificate.
    – lepe
    Nov 4, 2016 at 6:30
  • I have created a script for this solution plus -set_serial - see my answer Jun 30, 2017 at 17:33
  • This answer saved me a whole lot of work, after spending almost a day on an issue that required this, i was nearly about to give up, i tip my hat to you for this! Nov 24, 2017 at 12:58
4

Basic mode to extend the valid period of root (you need the public X.509 and asociated private key):

Generate the CSR from public X.509 and private key:

openssl x509 -x509toreq -in XXX.crt -signkey XXX.key -out XXX.csr

Re-sign the CSR with private key:

openssl x509 -in XXX.csr -out XXX.crt -signkey XXX.key -req -days 365
1
  • These commands worked for me, running a local/self-signed CA, while the top answer failed with unable to verify the first certificate during openssl verify.
    – relet
    Nov 30, 2020 at 12:34
4

@Bianconiglio plus -set_serial worked for me. My server is intranet only so I am not worrying to much what the side effects are and I now have time to work on a "proper" solution.

I used the following configurable script. Just set the variables CACRT, CAKEY and NEWCA.

# WF 2017-06-30
# https://serverfault.com/a/501513/162693
CACRT=SnakeOilCA.crt
CAKEY=SnakeOilCA.key
NEWCA=SnakeOilCA2017
serial=`openssl x509 -in $CACRT -serial -noout | cut -f2 -d=`
echo $serial
openssl x509 -x509toreq -in $CACRT -signkey $CAKEY -out $NEWCA.csr
echo -e "[ v3_ca ]\nbasicConstraints= CA:TRUE\nsubjectKeyIdentifier= hash\nauthorityKeyIdentifier= keyid:always,issuer:always\n" > $NEWCA.conf
openssl x509 -req -days 3650 -in $NEWCA.csr -set_serial 0x$serial -signkey $CAKEY -out $NEWCA.crt -extfile ./$NEWCA.conf -extensions v3_ca
openssl x509 -in $NEWCA.crt -enddate -serial -noout
3

When your root certificate expires, so do the certs you've signed with it. You will have to generate a new root cert and sign new certificates with it. If you don't want to repeat the process every few years the only real option is to extend the valid date on the root cert something like ten or twenty years: The root I generated for my own use I set out twenty years.

You can't "renew" a root cert. All you can do is generate a new one.

Generate a new root 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 teething problems with the new one resolved.

As far as the VPN tunnels go, I would set up a couple of testbed servers to experiment with so you understand precisely what you have to do before you do it with a client's machine.

3
  • This reply seems to suggest that it is possible to renew a root certificate, by re-using its key. But I suspect this is no different from starting from scratch, as the new cert will have a different signature, and hence won't validate existing client certs.
    – Remy Blank
    Sep 4, 2011 at 11:47
  • yes, you can extend valid period... and is less work than recreate all pki, client certificates, and retrust new root...
    – ggrandes
    Jan 22, 2013 at 16:25
  • The part about issuing new end-entity certificates is not necessarily true. It depends on how the Authority Key Identifier (AKID) is represented in the subordinates CAs and end-entity certificates. If the AKID is based on {Distinguished Name, Serial Number}, then continuity will be achieved. Also see RFC 4518, Internet X.509 Public Key Infrastructure: Certification Path Building.
    – user145545
    Mar 31, 2016 at 21:59
0

We have had the same issue, and that was in our case because the Debian server was out to date, and the openSSL had this issue:

https://en.wikipedia.org/wiki/Year_2038_problem

The last version of OpenSSL available for Debian 6 brings this problem. All certificates created after 23.01.2018 produces a Vality: for 1901 year !

The solution is to update the OpenSSL. You can create again the config files (with the certificates) for the clients.

0

The answer https://serverfault.com/a/308100/971795 seems to suggest it's not necessary to renew the private key - only renew the public key certificate is enough. However, it is best practice to rotate the private key of root CA once in a while.

The procedure is to "replace" the old CA with a new one (not just the public key certificate, but the entire CA), by

  1. Create a new CA and start issuing new certificates from it
  2. Disable issuance on old CA, BUT KEEP certificate revocation/validation
  3. Wait for all the certificates issued by the old CA to expire (you can generate an audit report on the old CA)
  4. shut down the old CA

Note that step 2, 3 ensures the smooth transition from old to new CA.

For more detail, check out https://docs.aws.amazon.com/acm-pca/latest/userguide/ca-lifecycle.html#ca-succession

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .