130

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.

HopelessN00b
  • 53,385
  • 32
  • 133
  • 208
Remy Blank
  • 1,925
  • 3
  • 14
  • 11

7 Answers7

181

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!

Shane Madden
  • 112,982
  • 12
  • 174
  • 248
  • Awesome reply, thanks! So all hope is not lost, and I will only have to upload the new root cert to all clients for them to trust? That's even better than I thought, because OpenVPN allows multiple CA certificates in one file, so I can simply put both the old and new CA cert into a single file and the transition should be seamless. – Remy Blank Sep 04 '11 at 20:47
  • @Remy Yup - you'll need to make sure that anything that's presenting a certificate chain starts presenting the new one before the old one expires, and you'll probably want to get the old one out of the trusted roots before it expires, but all of the certs issued against the old root should validate with no problem against the new root. – Shane Madden Sep 05 '11 at 17:13
  • 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 '13 at 19:00
  • 2
    @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](http://security.stackexchange.com/q/11949/4479) for more info. – Shane Madden Aug 23 '13 at 01:19
  • 3
    In addition to the above, I found that the serial number needs to be the same for this method to work. – Scott Presnell Aug 25 '14 at 14:44
  • @Brunis Uh, well, I showed in the answer that it worked and several of the comments confirmed, so if it's not working for you then you should probably post a new question with the problem you're having. – Shane Madden Dec 23 '14 at 17:28
  • Very useful! One question: why no -x509 option the "10 years pass" section? – jldugger Jul 15 '15 at 01:27
  • I think you have to keep the same values (country, state ... common name, etc) or it will fail (please correct me if I'm wrong). – lepe Nov 04 '16 at 06:26
  • 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](https://tools.ietf.org/html/rfc4158)? 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. –  Nov 10 '16 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). – Shane Madden Nov 10 '16 at 18:18
  • 1
    @Shane - That answer ***is*** being referenced and used in the wild. See, for example, [Renew Certification Authority in OPENSSL Verify fails](http://stackoverflow.com/q/40533748/608639) on Stack Overflow. I'm here because the OP cited it. –  Nov 10 '16 at 18:21
  • @jww What I'm seeing there is someone who understood the context of my "here's how you verify this works in a lab" section, and doesn't seem to have copied in any bad information into their question - they don't discuss issuing their client certs at all. I guess you just mean that you got linked over here, and took exception to the exact procedure that I used to generate the lab cert - but wanted to prove me wrong in comments instead of just submitting an edit to make it a "safe" generated serial number? – Shane Madden Nov 10 '16 at 18:29
18

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
pevik
  • 286
  • 1
  • 12
Bianconiglio
  • 181
  • 1
  • 2
  • 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 02 '14 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 '15 at 13:27
  • This method is easier as it keeps the same information than the previous certificate. – lepe Nov 04 '16 at 06:30
  • I have created a script for this solution plus -set_serial - see my answer – Wolfgang Fahl Jun 30 '17 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! – Onitlikesonic Nov 24 '17 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
ggrandes
  • 181
  • 8
  • 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 '20 at 12:34
3

@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
pevik
  • 286
  • 1
  • 12
Wolfgang Fahl
  • 585
  • 1
  • 5
  • 13
1

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.

Snowhare
  • 157
  • 2
  • [This reply](http://serverfault.com/questions/285957/certificate-authority-expiration/285961#285961) 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 04 '11 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 '13 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](https://tools.ietf.org/html/rfc4158). –  Mar 31 '16 at 21:59
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

yilin
  • 1
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.

Tolsadus
  • 1,123
  • 11
  • 22
Manuel
  • 1