1

I have a web application running on Ubuntu 16.04.3 server and in a development environment, I have a self signed X509 certificate generated and configured under Apache2.0.48. This all works just fine.

An example command that I use within a build script to generate the X509 is as follows:

openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /var/www/ssl/selfSigned.key -out /var/www/ssl/selfSigned.crt -subj "/C=US/ST=California/L=Somewhere/O=SomeGroup/OU=SomeOU/CN=192.168.0.150"

Certificate Issues

I've recently introduced a 3rd party JAVA application (Spring framework apparently) within my application and I've been working to integrate it into my application. Their support team have been fantastic in getting things working in an HTTP environment, and have directed me to this link to set up a Spring application under HTTPS using self signed X509s.

I update my application.properties file with changes as follows:

server.port=8181
security.require-ssl=true
server.ssl.key-store-type=PKCS12
server.ssl.key-store=/var/www/secure/ssl/keystore.p12
server.ssl.key-store-password=123456
server.ssl.key-alias=server1

Using the simple import command (as per 1.b on the link)

keytool -import -keystore /var/www/ssl/keystore.p12 -storepass 123456 -noprompt -alias server1 -file /var/www/ssl/self-signed.crt

the certificate appears to get inserted into the keystore ok, but when I restart the 3rd party service to read the new parameters, I get this

Jun 15 19:32:08 ubuntu java[7016]: ***************************
Jun 15 19:32:08 ubuntu java[7016]: APPLICATION FAILED TO START
Jun 15 19:32:08 ubuntu java[7016]: ***************************
Jun 15 19:32:08 ubuntu java[7016]: Description:
Jun 15 19:32:08 ubuntu java[7016]: The Tomcat connector configured to listen on port 8181 failed to start. The port may already be in use or the connector may be misconfigured.
Jun 15 19:32:08 ubuntu java[7016]: Action:
Jun 15 19:32:08 ubuntu java[7016]: Verify the connector's configuration, identify and stop any process that's listening on port 8181, or configure this application to listen on another por
Jun 15 19:32:08 ubuntu systemd[1]: 3ps.service: Main process exited, code=exited, status=1/FAILURE
Jun 15 19:32:08 ubuntu systemd[1]: 3ps.service: Unit entered failed state.
Jun 15 19:32:08 ubuntu systemd[1]: 3ps.service: Failed with result 'exit-code'.

I wondered if it was the certificate, so I then decided to use keytool to generate one instead of openssl (note the use of a test keystore which I updated my application.properties to use):

keytool -genkeypair -alias server1 -keyalg RSA -keysize 2048 -keystore /var/www/secure/ssl/test.p12 -storetype PKCS12 -validity 3650

When I use this, the service at least starts (even if the application doesn't work as expected) so I can only assume that the certificate needs to be converted.

Googling shows that it's reasonably simple to convert my existing certificates from PEM (PKCS10 format I assume, as I'm using "req"?) to PKCS12 so I try that with the following command:

openssl pkcs12 -export -out certificate.pfx -inkey self-signed.key -in self-signed.crt

(I leave the export password as blank so as not to keep having to type it in when services restart). Then I take my new PKCS12 certificate and import it (noting a new keystore too):

keytool -import -keystore test2.p12 -storepass 123456 -noprompt -alias server1 -file certificate.pfx

But that command fails with keytool error: java.lang.Exception: Input not an X.509 certificate

I've also tried

openssl crl2pkcs7 -nocrl -certfile self-signed.crt -out self-signed.p7b
keytool -import -keystore test.p12 -storepass 123456 -noprompt -alias server1 -file self-signed.p7b

... and get the same error (not an X.509 certificate)

I've Googled how to convert these certificates between various formats and into a format that keytool can use (and the service starts correctly) but I seem to be getting into a never-ending loop and no further forward.

From what I initially see, I don't believe that there's anything wrong with the 3rd party application itself, as it runs under HTTP just fine; and adding HTTPS to Spring appears to be very simple. I'm not a JAVA guru and so I can only surmise that something's amiss with the certs.

Can anyone see where I'm going wrong?

bnoeafk
  • 489
  • 4
  • 16

1 Answers1

2

You are confusing two different things: a certificate that identifies someone else you trust (often but not always a CA = Certificate Authority), and a certificate PLUS PRIVATE KEY that identifies yourself (your own system). An SSL/TLS server must have a certificate PLUS PRIVATE KEY.

keytool -import -keystore /var/www/ssl/keystore.p12 -storepass 123456 -noprompt -alias server1 -file /var/www/ssl/self-signed.crt

This works only for the first case, a certificate that identifies someone else you trust. It is useless and wrong for your case.

Googling shows that it's reasonably simple to convert my existing certificates from PEM (PKCS10 format I assume, as I'm using "req"?) to PKCS12 so I try that with the following command:

openssl req by default creates a CSR (Certificate Signing Request) which is PKCS10, but you did openssl req -x509 which creates a certificate (not a CSR) and in particular a self-signed certificate, and in some cases including yours also creates the corresponding private key. Neither a certificate nor a private key is PKCS10. The certificate is a certificate; for reasonably recent OpenSSL and since you specified -nodes (whose spelling is a historical relic and now quite outdated) the private key is PKCS8-unencrypted (technically ASN.1 type PrivateKeyInfo rather than EncryptedPrivateKeyInfo).

openssl pkcs12 -export -out certificate.pfx -inkey self-signed.key -in self-signed.crt

You were almost there.

(I leave the export password as blank so as not to keep having to type it in when services restart).

PKCS12 is designed to be always password-encrypted and leaving the password 'blank' is a nonstandard case that doesn't work consistently between OpenSSL and Java. But you shouldn't need to type anything at startup, the key-store-password setting should handle that.

Then I take my new PKCS12 certificate and import it (noting a new keystore too):
keytool -import -keystore test2.p12 -storepass 123456 -noprompt -alias server1 -file certificate.pfx

That doesn't work at all. -import imports only a trusted certificate (to a new entry), or a certificate chain in X.509, 'PkiPath', or PKCS7 format matching an existing private-key entry (normally one generated in Java). It does not import a PKCS12 format file under any circumstance.

PKCS12 is already a suitable keystore for modern Java. If you wanted to convert it to an older-format JKS keystore, as some older Java systems or programs need or prefer, -importkeystore can do that; see the manual or search for dozens of existing Qs on that. Note you named your PKCS12 with suffix pfx but that doesn't change the contents, and anyway for practical purposes PFX and PKCS12 are the same thing.

Go back to pkcs12 -export and use the password in your server config. Personally I'd also use a filename ending in p12 for clarity, but any name that matches the server config should work.

dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70
  • I actually found an article on Oracle's site that I went through - I basically created the server I was running everything on as a root CA and then set up a CSR and signed it with that root CA. Getting everything into the keystore was pretty simple to the point that the Spring service I had been using started without issue. I **believe** that it's the application that has an issue, as opposed to JAVA itself as the response from the support team is to use HTTP and not HTTPS, which I'm not overly satisfied with, but until I find a better answer... – bnoeafk Jun 18 '18 at 14:41