Maybe I will find help here. I want to enable SSL on Spring Boot application. I have a configuration like:
server: port: 8999 ssl:
enabled: true
key-store: classpath:keystore.jks
key-store-password: mypass
key-password: mypass
The problem is my keystore. I've imported *crt file into keystore with alias 'tomcat':
keytool -importcert -file certificate.crt -keystore native.jks -alias tomcat
However, I still can't properly access my rest api. It vomits with error in firefox:
SSL_ERROR_RX_RECORD_TOO_LONG
it doesn't work. How can I make proper keystore to make it work? I'm issuing with CA certificate, NOT self-signed. I have files like:
certificate.crt, certificate.p12, certificate.pk, privkey.pem and
three files root_ca_1.ca-bundle, root_ca_2.ca-bundle,
root_ca_3.ca-bundle
. That's all I have. I'm very fresh with ssl topic, just read some tutorials and tried few keytool commands to make it work. I'd be grateful for help. Thank You in advance.
I just spent the afternoon figuring out this exact problem, so I'll share my process here.
Each of the references below provides instructions on how to generate and use a self-signed certificate. That's not exactly what I'm trying to do, but these each contain some useful background information.
REFERENCES:
https://www.baeldung.com/spring-boot-https-self-signed-certificate
https://mkyong.com/spring-boot/spring-boot-ssl-https-examples/
https://dzone.com/articles/how-to-enable-the-https-into-spring-boot-applicati
I have already purchased a real CA-issued SSL certificate for the *.jimtough.org 'wildcard' domain. I purchased the certificate from http://www.namecheap.com/, but the actual Certificate Authority (CA) is Comodo.
As part of the purchase/activation procedure with the CA, I needed to follow these instructions:
https://www.namecheap.com/support/knowledgebase/article.aspx/9592/14/generating-a-csr-on-amazon-web-services-aws/
Note that I opted to follow their AWS instructions because I am an AWS user and have an EC2 server readily available with OpenSSL and Java already installed on the server. There are lots of other alternatives to do the same procedure, so search further to find the 'generating a CSR' instructions that are right for you.
At the end of this step, I have the following two files:
csr.pem - This is used as part of the SSL cert request/activation process
private.key - This is the private key part of my SSL cert, which I will need later to install the cert on my servers. Keep it secret. Keep it safe.
After I completed the purchase and verification procedure for my SSL cert, the CA sent me back a .zip file that contained a .p7b, .crt, and .ca-bundle file.
One of the reference links below explains the difference between these certificate file types:
.p7b - This type should be compatible with Java-based applications (PKCS#7 format)
.crt - This type should be compatible with most everything else - the link above suggests this is PEM format
.ca-bundle - Not sure when to use this - the link above suggests this is PEM format
REFERENCES:
https://www.ssls.com/knowledgebase/what-are-certificate-formats-and-what-is-the-difference-between-them/
Next I need to figure out how to use the files that I listed above to configure my Spring Boot application for HTTPS.
I will follow the relevant parts of the below tutorials to get what I need:
https://www.baeldung.com/spring-boot-https-self-signed-certificate
https://www.baeldung.com/x-509-authentication-in-spring-security
NOTE: In both tutorials, I will NOT follow their sections on creating a self-signed certificates, since I already possess a real certificate that was issued by a real CA.
The first relevant step in their instructions is to create a new Java keystore. The requirements are:
Must have Java installed, so I have access to the 'keytool' utility
Must have the 'openssl' utility installed, so I can create a .p12 file using my .key and .p7b files as input
I will use my AWS EC2 Linux server to do this. My server already has the Java/keytool and OpenSSL utilities installed.
First I need to use the OpenSSL utility to create a .p12 file that (if I understand correctly) will contain both my
private key, and the CA-issue certificate. Second, I need to create a new Java keystore that will contain an imported
copy of the .p12 file.
openssl pkcs12 -export -out jimtough-dot-org.p12 -name "jimtough-dot-org" -inkey private.key -in __jimtough_org.crt
IMPORTANT: You need to provide a password at the 'export password' prompt, otherwise the keytool import in the next step will fail
keytool -importkeystore -srckeystore jimtough-dot-org.p12 -srcstoretype PKCS12 -destkeystore jimtough-dot-org-keystore.jks -deststoretype JKS
You will need to provide the password you used in the 'openssl' command
You will also need to provide a new password for the keystore that you are creating
(OPTIONAL) keytool -importkeystore -srckeystore jimtough-dot-org-keystore.jks -destkeystore jimtough-dot-org-keystore.pkcs12 -deststoretype pkcs12
I received a warning from 'keytool' about JKS being a proprietary format, and a suggestion that I convert my keystore to PKCS12 format, so I did so with this optional command
Finally, I need to package my newly created Java keystore with my Spring Boot application and configure the application to use it.
REFERENCES:
https://www.baeldung.com/spring-boot-https-self-signed-certificate
https://www.baeldung.com/x-509-authentication-in-spring-security
I referred back to the two Baeldung tutorials above, and was able to get the details I needed to make my Spring Boot (with Spring Security enabled) to work.
I created a new 'keystore' folder under the existing 'src/main/resources', and copied both of my newly created keystore files there (I kept both formats).
I added the block below to my Spring Boot application's application.properties file.
#--------------------------------------------------------------------------------------------------
# SSL CONFIGURATION
# The format used for the keystore. It could be set to JKS in case it is a JKS file
#server.ssl.key-store-type=JKS
server.ssl.key-store-type=PKCS12
# The path to the keystore containing the certificate
#server.ssl.key-store=classpath:keystore/jimtough-dot-org-keystore.jks
server.ssl.key-store=classpath:keystore/jimtough-dot-org-keystore.pkcs12
server.ssl.key-store-password=mykeystorepassword
server.ssl.key-alias=jimtough-dot-org
server.ssl.enabled=true
server.port=8443
#--------------------------------------------------------------------------------------------------
As expected, I get a bunch of warnings from my browser when I attempt to connect to a locally running instance of the Spring Boot application using https://localhost:8443/ as the URL. This happens because the browser correctly identifies the mismatch between 'localhost' and the expected 'jimtough.org' domain that my SSL certificate was created to run on. There shouldn't be any warnings when I deploy the application to a server whose hostname is 'anything.jimtough.org' (or just www.jimtough.org).
That's it! Happy HTTPS'ing!
Don't use spring-boot for SSL-connections. Let a reverse proxy handle the SSL-termination.
So it is possible, that a tool can automatic renew your certificates (like the certbot).
And you don't need to put a (sercret) private-key to your application.
It is simpler to share your application. A server-admin needs only to setup reverse proxy (or have something familar already in cloud-systems like kubernetes) and can scale up your application.
Benefits
Scalable application
Simpler spring-setup
No secrets in your application
Simpler use of application (#cloudSystems)
Most reverseProxies are compatible with certbot
Well, you require few more properties to be added in ssl configuration
server:
ssl:
key-store: classpath:config/tls/keystore.p12
key-store-password: password ##this will be your certificate password
key-store-type: PKCS12
ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
enabled-protocols: TLSv1.2
http2:
enabled: true
Make sure that the p12 keystore file is present under classpath (src/main/resources) in config/tls
But to generate keystore file use the below openssl command where you
will use .crt and .key file to generate .p12 file.
.crt and .key are present under Folder CA and file p12 file will be
generated under CA
Please note that you will asked for the certificate password after
running the below command
openssl pkcs12 -export -in CA/certificate.crt -inkey CA/certificate.key -name certificate -out CA/certificate.p12
If you want to add this certificate to your local cacert then use the
below command
under jre\lib\security
keytool -importcert -noprompt -trustcacerts -alias ca.certificate -file CA/certificate.crt -keystore cacerts -storepass changeit
Related
when I am creating Restservices in java using GET, POST etc then I am requesting them using
http protocol. as soon as i use https it gives error.
for eg : http://localhost:8080/demorest/webapi/aliens is working properly.
but when I query same using https
https://localhost:8080/demorest/webapi/aliens
I get error site can not provide secured connection
what modification is required to make them compatible with https.
As you mentioned you are new to APIs here is a detailed answer for you.
Answer is based on assumption that you are using tomcat server. There is 4 step approach to have application running on https, red below
Get an SSL certificate or Generate a self-signed SSL certificate
Enable HTTPS in application
Redirect HTTP to HTTPS
Distribute the SSL certificate to clients.
If you dont already have ssl certificate generate yourself using keytool.
Keytool is a certificate management utility provided together with the JDK, so if you have the JDK installed, you should already have keytool available.
Let's open our Terminal prompt and write the following command to create a JKS keystore:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -keystore
keystore.jks -validity 3650 -storepass password
To create a PKCS12 keystore, and we should, the command is the following:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -storetype
PKCS12 -keystore keystore.p12 -validity 3650 -storepass password
Let's have a closer look at the command we just run:
genkeypair: generates a key pair;
alias: the alias name for the item we are generating;
keyalg: the cryptographic algorithm to generate the key pair;
keysize: the size of the key. We have used 2048 bits, but 4096 would be a better choice for production;
storetype: the type of keystore;
keystore: the name of the keystore;
validity: validity number of days;
storepass: a password for the keystore.
When running the previous command, we will be asked to input some information, but we are free to skip all of it (just press Return to skip an option). When asked if the information is correct, we should type yes. Finally, we hit return to use the keystore password as key password as well.
What is your first and last name?
[Unknown]: What is the name of your organizational unit?
[Unknown]: What is the name of your organization?
[Unknown]: What is the name of your City or Locality?
[Unknown]: What is the name of your State or Province?
[Unknown]: What is the two-letter country code for this unit?
[Unknown]: Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: yes
Enter key password for <tomcat>
(RETURN if same as keystore password):
Verify the keystore content
To check the content of the keystore following the JKS format, we can use keytool again:
keytool -list -v -keystore keystore.jks
To test the content of a keystore following the PKCS12 format:
keytool -list -v -storetype pkcs12 -keystore keystore.p12
Convert a JKS keystore into PKCS12
Should we have already a JKS keystore, we have the option to migrate it to PKCS12; keytool has a convenient command for that:
keytool -importkeystore -srckeystore keystore.jks -destkeystore
keystore.p12 -deststoretype pkcs12
2.) To Enable https in your project
If you have a application.properties file
server.port=8443
server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=password
server.ssl.key-alias=tomcat
security.require-ssl=true
If you have application.yml file
server:
ssl:
key-store: classpath:keystore.p12
key-store-password: password
key-store-type: pkcs12
key-alias: tomcat
key-password: password
port: 8443
To achieve in application, we need to extend the WebSecurityConfigurerAdapter class, since the security.require-ssl property has been deprecated.
if you are on older version then you can skip below mentioned code.
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requiresChannel()
.anyRequest()
.requiresSecure();
}
}
3.) Redirect http to https
Now that we have enabled HTTPS in our Spring Boot application and blocked any HTTP request, we want to redirect all traffic to HTTPS.
Spring allows defining just one network connector in application.properties (or application.yml). Since we have used it for HTTPS, we have to set the HTTP connector programmatically for our Tomcat web server.
#Configuration
public class ServerConfig {
#Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
#Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(getHttpConnector());
return tomcat;
}
private Connector getHttpConnector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}
4.) Distribute the SSL certificate to clients
When using a self-signed SSL certificate, our browser won't trust our application and will warn the user that it's not secure. And that'll be the same with any other client.
It's possible to make a client trust our application by providing it with our certificate.
Extract an SSL certificate from a keystore
We have stored our certificate inside a keystore, so we need to extract it. Again, keytool supports us very well:
keytool -export -keystore keystore.jks -alias tomcat -file
myCertificate.crt
Make a browser trust an SSL certificate
When using a keystore in the industry-standard PKCS12 format, we should be able to use it directly without extracting the certificate.
I suggest you check the official guide on how to import a PKCS12 file into your specific client.
If deploying the application on localhost, we may need to do a further step from our browser: enabling insecure connections with localhost.
In Chrome, we can write the following URL in the search bar: chrome://flags/#allow-insecure-localhost and activate the relative option.
Import an SSL certificate inside the JRE keystore
To make the JRE trust our certificate, we need to import it inside cacerts: the JRE trust store in charge of holding all certificates that can be trusted.
First, we need to know the path to our JDK home. A quick way to find it, if we are using Eclipse or STS as our IDE, is by going to Preferences > Java > Installed JREs. If using IntelliJ IDEA, we can access this information by going to Project Structure > SDKs and look at the value of the JDK home path field.
Then, from our Terminal prompt, let's insert the following command (we might need to run it with administrator privileges by prefixing it with sudo):
keytool -importcert -file myCertificate.crt -alias tomcat -keystore
$JDK_HOME/jre/lib/security/cacerts
you can refer project on github here
It depends, your rest services might run on Tomcat or Spring Boot so should read their documentation, you can also use a different https service like nginx that proxies all or parts of the requests from https to http.
First check https protocol using the same port as 8080? in most of the cases http (8080) and https(8443 or 443) use different ports.
If port is correct then import the certificate.
https://stackoverflow.com/a/27928213/5662508
It would be helpful if you can give the sever you are using, also would be always nice if the java version, frameworks(if any) and their version and in this case of-course the server and the server version.
In the link mentioned here on DZone you can find an example of how to set up https locally with tomcat server in a java application, else you can also try with a more generic article not specific to java here on freecodecamp
Step 1 : You can create a keystore using java keytool;
Command : keytool -genkey -alias {any-name} -keyalg RSA -keystore {path to store the keystore}
Step 2 : You can go to your server config file such as conf/server.xml for Tomcat and uncomment the 8443 setting and then add the following in the end before tag closing;
keystoreFile="{path to keystore}"
keystorePass="{Password you set while creating the keystore}" />
Step 3 : Now restart the server and hit "https://localhost:8443/demorest/webapi/aliens".
Happy coding!
I have set up a Spring Boot application to utilize HTTPS with a certificate (not self-signed) in a PKCS12 keystore.
I created the keystore like this:
openssl pkcs12 -export -inkey key -in cert -certfile interm -out tls-keystore.p12 -name tomcat
The configuration properties:
server.ssl.key-store=/etc/app/tls-keystore.p12
server.ssl.key-store-password=password
server.ssl.key-alias=tomcat
I am using a trust store (a different file) which is a copy of the default JVM keystore with two extra certs inserted (so we can talk to a local service that uses self-signed certs).
The SSL works, but there are a number of warnings in the log:
2020-03-12 13:23:14.842 WARN 11572 --- [ main] org.apache.tomcat.util.net.SSLUtilBase : jsseUtil.trustedCertNotValid
There are 30 of these. It doesn't seem like they can correspond to certificates in the keystore I've created, because it only has one entry.
Looking at the code it appears that the warning was intended to be rendered as a more informative message, but failed: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SSLUtilBase.java?revision=1854079&view=markup&pathrev=1854079#l296
If either SSL or the alternate trust store are turned off, the warnings don't appear.
I did enable debugging: -Djavax.net.debug=ssl:handshake:keymanager:trustmanager -Djava.security.debug=jca,certpath,provider
which resulted in quite a bit of extra information logged, but none adjacent to the warnings in question.
What is causing these warnings and what should I do about them?
Cloud databases are very prevalent today and sometimes we need to connect to one from a laptop or similar. Usually there is an option for an unencrypted connection but that's not very secure. So how do I connect to a mutual TLS mysql server (like google cloud SQL)?
From mysql cli it's rather straight-forward after downloading the server ca cert, client cert and key from google cloud console:
mysql -u <user-name> -h <server-ip> -p --ssl-ca=server-ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem
Note: for Google cloud you can also use the Cloud SQL Proxy but I want to connect without that
While not is not exactly an answer to the question I will add this example of how to make this work with logstash jdbc plugin deployed on kubernetes since it was not completely straight-forward and it might be useful for similar systems.
This solution is based on the first solution but the truststore must be based on the full cacerts of the jvm.
In your input definition add the parameters to the jdbc URL:
input {
jdbc {
...
jdbc_connection_string => "jdbc:mysql://<server-ip>:3306/<db>?verifyServerCertificate=true&useSSL=true&requireSSL=true"
jdbc_password => "${MYSQL_PASSWORD}"
...
}
}
Then create a secret from the trust- and keystore and for mysql password:
kubectl create secret generic java-tls-creds --from-file=./keystore.jks --from-file=./truststore.jks
kubectl create secret generic mysql-password --from-literal='password=<password>'
Then we modify the deployment yaml to mount the credentials and add the LS_JAVA_OPTS to point to them:
apiVersion: apps/v1
kind: Deployment
...
env:
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-password
key: password
- name: LS_JAVA_OPTS
value: -Djavax.net.ssl.keyStore=/java-tls-creds/keystore.jks -Djavax.net.ssl.keyStorePassword=<password> -Djavax.net.ssl.trustStore=/java-tls-creds/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit
...
volumeMounts:
- name: java-tls-creds
mountPath: "/java-tls-creds"
readOnly: true
...
volumes:
- name: java-tls-creds
secret:
secretName: java-tls-creds
Logstash 7 and jvm 9+ below.
OK, I finally figured it out piecing together information from different sources. This solution is tested with google cloud SQL and hibernate but should work in other setups as well.
The solution requires using java keystore (client cert/key) and truststore (server-ca cert) and passing some jdbc URL params and JVM options.
First off, lets create a truststore from the server-ca.pem file:
keytool -importcert -alias gcpRoot -file server-ca.pem -keystore truststore.jks -storepass <chose a password and remember>
EDIT: Or add CA to jvms existing cacerts file (to ensure other https calls will work), copy cacerts it rename to truststore.jks and run:
OR: keytool -importcert -alias gcpRoot -file server-ca.pem -keystore truststore.jks -storepass changeit
Secondly, we need to import the client cert and key to a keystore file in two steps (I used my SQL username as alias but I don't think it matters)
openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out keystore.p12 -name "<keystore-alias>" -passout pass:<chose a password and remember>
keytool -importkeystore -alias <keystore-alias> -srckeystore keystore.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -srcstorepass <insert same password here> -deststoretype JKS -deststorepass <password-for-output-jks-keystore>
Next, we need to modify the jdbc connection URL (NOTE! Some IDEs - like intelliJ - requires & to be escaped and be replaced with &
jdbc:mysql://<server-ip>/<db-name>?verifyServerCertificate=true&useSSL=true&requireSSL=true
Finally we need to provide location and passwords for keystore and truststore as JVM parameters:
-Djavax.net.ssl.trustStore="truststore.jks"
-Djavax.net.ssl.trustStorePassword="<password>"
-Djavax.net.ssl.keyStore="keystore.jks"
-Djavax.net.ssl.keyStorePassword="<password>"
Update:
If you are running on a jvm version 9 or above (like logstash docker images for 7+) there are some class-loading issues to be worked around to get the jdbc driver to even load and you need a recent version of the mysql driver for TLS to work.
First you apparently have to put the .jar file of the jdbc driver in <logstash-dir>/logstash-core/lib/jars/mysql-connector-java-8.0.17.jar (this will cause the jar to be loaded automatically). And we also need to add the following to the input config:
jdbc_driver_library => ""
jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
For some reason I still get the warning Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver'` but it works despite this warning.
I'm trying to get JMX working under Tomcat 7.0.23 with SSL. The servers are located in AWS, which means all the hosts are NATed, and I need to use JmxRemoteLifecycleListener to explicitly set the two ports used by JMX. I've been doing a lot of reading on the subject but I just can't get all the pieces working together properly.
I can get JMX working fine without SSL. I have downloaded the version of catalina-jmx-remote.jar for my version of Tomcat and installed it in my tomcat/lib directory. My server.xml contains:
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
rmiRegistryPortPlatform="1099" rmiServerPortPlatform="1098" />
When I launch Tomcat with the following settings I can connect with an insecure session:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access
-Djava.rmi.server.hostname=<public IP of server>
-Dcom.sun.management.jmxremote.ssl=false
However if I change these to the following then I'm unable to establish an SSL connection:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password
-Dcom.sun.management.jmxremote.access.file=/path/to/jmxremote.access
-Djava.rmi.server.hostname=<public IP of server>
-Dcom.sun.management.jmxremote.ssl=true
-Dcom.sun.management.jmxremote.ssl.need.client.auth=false
-Dcom.sun.management.jmxremote.authenticate=true
-Djavax.net.ssl.keyStore=/path/to/keystore.dat
-Djavax.net.ssl.keyStorePassword=<password>
-Djavax.net.ssl.trustStore=/path/to/truststore.dat
-Djavax.net.ssl.trustStorePassword=<password>
keystore.dat contains just a single certificate created via:
openssl x509 -outform der -in cert.pem -out cert.der
keytool -import -alias tomcat -keystore keystore.dat -file cert.der -storepass <password>
truststore.dat contains a full copy of the java cacerts plus the CA cert for my self-signed cert:
cp $JAVA_HOME/jre/lib/security/cacerts truststore.dat
keytool -storepasswd -storepass changeit -new <password> -keystore truststore.dat
keytool -import -trustcacerts -file mycacert.pem -alias myalias -keystore truststore.dat -storepass <password>
After launching Tomcat I've tried connecting via jconsole but it can't establish a connection. I tried to verify SSL using openssl but it looks like Tomcat isn't making use of the cert:
$ openssl s_client -connect <host>:1099
CONNECTED(00000003)
140735160957372:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 322 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
I've verified that my local keystore and truststore are set up properly by exporting the keys and verifying the cert chain (combined.pem is all the CA certs from truststore.dat and cert.pem is my cert from keystore.dat):
$ openssl verify -verbose -purpose sslserver -CAfile combined.pem cert.pem
cert.pem: OK
So now I'm at a complete loss. The cert and CA cert look correct. Unencrypted JMX connections work. But I can't seem to get the connection to use SSL. What am I missing here?
I don't know if this is just a red herring or not, but I don't see any way to specify what cert in the keyStore is used by JMX. Some of what I read implies that it just uses a cert with the alias "tomcat". Is that correct?
You are starting the RMI Registry on port 1099. In order for the RMI Registry to utilize SSL you need to pass an additional -Dcom.sun.management.jmxremote.registry.ssl=true argument.
Edit:
Do you use jconsole -J-Djavax.net.ssl.trustStore=truststore -J-Djavax.net.ssl.trustStorePassword=trustword -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password to start JConsole? It needs to know where the stores are and the corresponding passwords.
For VisualVM you can install VisualVM-Security plugin which will add a new tab to the Options dialogue allowing you customize the SSL related options in UI.
I wanted tomcat getting to work with jmx and ssl and followed Bruce setup. In case someone runs int the same problem: using the openssl and keytool commands form Bruce I was getting at client ssl errors:
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Not sure why but the figerprint on one side was 5 chars longer at the beginning.
I recreated the keystore using:
keytool -genkeypair -alias tomcat -keyalg RSA -keystore keystore.jks -dname cn=test,ou=test,dc=example,dc=com
In tomcat sever.xml I added the listener as Bruce suggested.
Because client auth is set to false I do not add truststore in tomcat jmx configuration. Instead I added registry.ssl:
[...]
-Djavax.net.ssl.keyStorePassword=your_keystore_pass
-Dcom.sun.management.jmxremote.registry.ssl=true
Then on client side as J.B. suggested I download ssl plugin for visualvm and criss-cross the keystore resulting in:
visualvm -J-Djavax.net.ssl.trustStore=keystore.jks -J-Djavax.net.ssl.trustStorePassword=your_keystore_pass
When adding authentication make sure that your jmx access file looks like:
<user_name> readwrite
and your password file looks like:
<user_name> <your_password>
This solved my ssl jmx setup for testing with visualm vm.
Edit:
Had some issues with having the registry also over SSL, set by:
-Dcom.sun.management.jmxremote.registry.ssl=true
leading at client to throw:
Root exception is java.rmi.ConnectIOException: non-JRMP server at remote endpoint
Adding client auth authentication:
-Dcom.sun.management.jmxremote.ssl.need.client.auth=true
-Djavax.net.ssl.trustStore=truststore.jks
-Djavax.net.ssl.trustStorePassword=your_trust_store_pass
solved both jmx and its registry to use ssl.
I am attempting to create a keystore and truststore file from a self-signed certificate, for use in a HTTPRouter action, deployed within a JBoss ESB. I used openssl to retrieve the certificate of interest and generated a keystore file and a truststore file with the following commands:
keytool -import -alias ejb-ssl -file cert.der -keystore cert.truststore
keytool -import -alias ejb-ssl -file cert.der -keystore cert.keystore -trustcacerts
Before generating the keystore and truststore files, I am converting the certificate to X509 format, otherwise the keytool utility does not work, returning an exception with the message 'input not an x.509 certificate' exception. To convert the certificate of interest, I am using the following command:
openssl x509 -in cert.cer -outform DER -out cert.der
I then copied these files into the my ESB's 'esbcontent/META-INF' folder. Below are the properties I am setting for the HTTPRouter action
#Configurators
configurators=HttpProtocol
#HttpProtocol Config...
protocol-socket-factory=org.jboss.soa.esb.http.protocol.SelfSignedSSLProtocolSocketFactoryBuilder
keystore=/META-INF/keystore/cert.keystore
keystore-passw=password
truststore=/META-INF/truststore/cert.truststore
truststore-passw=password
When I deploy the ESB I am getting the following error:
Caused by: org.jboss.soa.esb.ConfigurationException: Invalid 'keystore' config. Must be valid URL.
Looking at the certificate retrieved from the third party webservice, all URL's look OK. Does anyone have any idea why JBoss would not accept the URL in the generated keystore? I'm starting to tear my hair out on this one!
Also, I have been trying to use the org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory for the protocol-socket-factory. When using this, the ESB deploys OK. However, the HTTPRouter does not seem to send the request to the third party web service. I've used SoapUI to establish the web service is ok, so I think it's a problem with my configuration of the HTTPRouter action.
Any help offered is greatly appreaciated!
This took me an awful long time to figure out, but the solution turned out to be very simple. The path to the keystore file must be absolute. It CANNOT BE RELATIVE! Therefore, replacing
'/META-INF/keystore/cert.keystore' path
with
'C:/dev/server/jboss/jboss-as/server/default/deploy/MyEsb.esb/META-INF/keystore/cert.keystore
Solved the problem!
Leaving the properties file with this absolute path isn't always suitable when wanting to deploy the ESB within various different environments (Windows and Ubuntu). I'm using gradle as my build tool, so I used the ReplaceTokens feature to replace the keystore token with the absolute path required. I suppose you could also copy the keystore file into the deploy directory so it's available for all ESB's who require it.
Hope this helps someone else who comes across this problem. Was a simple solution in the end, but there is no mention anywhere in the docs for the keystore file to be referenced with an absolute path. But, doing that fixed the issue for me.
Thanks