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:
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:
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!
Note I am omiting the "sudo" part of every command.
Note For security reasons, it is not recommended to use such commands with the -password mypassword
part as they may get stored on your command history file.
Your import command could have failed because of input format of mydomain.crt. Check whether you have in PEM or DER format:
openssl x509 -in mydomain.crt -inform DER
If it fails, it is probably already on PEM format, but if not, the output from that command is what the keytool must be fed, but you should use the whole chain instead.
Cabundle.cert
could have already the whole chain in order. Do a
grep CERTIFICATE Cabundle.cert
and check if there are 2-4 blocks of BEGIN CERTIFICATE
- END CERTIFICATE
. If so, make a copy of the file and edit it to strip out the "bag attributes" they sometimes include before each certificate that does not get along with import commands. Just leave the gibberish between the BEGIN and END lines (including them). If not, build your own chained file concatenating such blocks from your certificate, the issuer CA, etc up to the root CA.
Your file should look like:
----BEGIN CERTIFICATE----
MIEooujfalsdlflasdl
....
----END CERTIFICATE----
----BEGIN CERTIFICATE----
MIEooujfalsdlflasdl
....
----END CERTIFICATE----
----BEGIN CERTIFICATE----
MIEooujfalsdlflasdl
....
----END CERTIFICATE----
Repeat your last import command with the new file:
keytool -keystore mydomain.keystore -alias mydomain -import -file CertificateChain.pem
Best Answer
So I finally figured it out after days of searching thanks to the guide here, you don't even need to use the keytool at all since xeams supports PKCS12 certificates.
Create a PKCS12 that contains your
fullchain.pem
andprivkey.pem
:openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out synametrics.cert -name xeams
Copy your
synametrics.cert
to xeams' installation directory:cp synametrics.cert /etc/Xeams/config/
Create a
server.properties
file in the./config
folder if it doesn't exist already and append the parameters below into the file:javax.net.ssl.keyStore=config/synametrics.cert javax.net.ssl.keyStorePassword=password SSLCertificatePassword=password
Where pasword is the password you entered when you created the keystore with openssl.
Choose the PKCS12 keystore type in Xeams admin panel > SMTP Configuration > Configure SSL:
Enable the secure SMTP server and specify its port in xeams. Verify you can connect to your mail server on the specified ports:
openssl s_client -connect mail.example.com:465
FIX FOR WEAK DH KEY
You'll probably get an error from openssl about the DHKey used by xeams being too small, this is a xeams issue, not openssl or letsencrypt.
The problem was caused by xeams using a very weak ephemeral Diffie-Hellman public key, less than 1024 bits, when ideally, it shouldn't be less than 2048 bits. I tried so many things but this is what fixed it for me:
Update the jre that comes with xeams in
/etc/xeams/jre
with the ones in this article by synammetrics:a. Stop the xeams smtp service:
service xeams stop
b. Rename the jre folder in your xeams insallation directory:
mv -T jre jre.old
c. Grab the compressed jre for your machine's architecture from the link to the article above and extract it to the
/etc/xeams/jre/
directory, your new jre folder should contain the contents of compressed jre.d. Start xeams!
service xeams start
I hope this fixes it for someone out there. :)