I have an issue where a Spring Boot rest service application needs to run on HTTPS. This works fine locally with a self signed certificate added to my keystore.
When this is deployed to a production server and the live trusted signed cert added to the keystore on the production server the application fails to work on HTTPS. The application starts ok but going to the production URL on HTTPS returns no response.
Using openssl on the production server results in
openssl s_client -connect localhost:8888
CONNECTED(00000003)
140401679677256: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 263 bytes
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
I have no access to the production server.
Is there a way I can test with the live certificate and keystore locally and work out what the issue is? I can get a copy of the keystore from production just not access directly to the server.
Thanks.
Related
I have a spring boot backend project.I want to use my ssl cert.
This my application.properties file.
I create robotikg.p12 using with mycert.cert and mycert.key.Also i added mycert.cert in cacerts with using keytool.
When application send the request backend i got this error.I didn't understand where is wrong this config.
When self-signing a certificate or using a self-signed CA (Certificate Authority) to sign your server's certificate, every time you perform a request through another application (be it your own or the browser), you have to tinker with your app (or browser) so that it trusts the connection that is established between itself and the server.
Browsers have their own trust stores (a.k.a key stores) where they keep the trusted certificate chains. Your certificate though, is not signed by any of these trusted certificates.
My approach would be:
Create a CA (self signed)
Sign a Server certificate with this CA
Add the CA to your application's trust store, so that at the moment the TLS handshake is performed, the validation of the server's certificate will be performed against this trust store and thus result valid.
I'm having trouble understanding why Weblogic/Java are not sending the Client certificate requested by the server(IIS server) during SSL Handshake via the CertificateRequest message.
I have already checked and tried all the other questions/answer in SO such as :
Java not providing client certificate for mutual SSL?
and similar.
I have created a custom keystore called Identity.jks with only one Certificate entry and I've follwed the WL guides (and everything else I could find on the Internet) to do the right settings.
Here are the debug logs for the SSL handshake:
*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Supported Signature Algorithms: SHA512withRSA, SHA512withECDSA, SHA256withRSA, SHA384withRSA, SHA1withRSA, SHA256withECDSA, SHA384withECDSA, SHA1withECDSA, SHA1withDSA
Cert Authorities:
<Empty>
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
As you can see the server sends a CertificateRequest message but for some reasons the Cert Authorities is Empty. The client (Weblogic) in this case doesn't send the certificate. As you can see there is a warning message by the developers saying:
no suitable certificate found - continuing without client authentication
When I use SoapUI instead of Weblogic to communicate with the server the handshake succeeds. SoapUI sends the certificate contained in the Identity.jks keystore.
Can it be that SoapUI is less restrictive and sends the only certificate present in the keystore anyway while Weblogic is expecting from the server to find something in the Cert Authorities:
<Empty> ?
Since I've setup weblogic to use only that key with that alias I expect it to send it...
Anyone knows what are the criteria that Weblogic uses to find a matching client certificate?
Is my interpretation of the logs correct?
Any idea/help is welcome.
I've had a similar problem with a Java HTTP client. Depending on your IIS version the server may or may not be sending the certificate list back. Newer version don't.
Ensure that you have the full certificate chain and your client certificate in the keystore.
Since there seems to be an interest, I'm answering my own question on how we fixed it.
When writing Java clients to communicate with other servers via Two-Way SSL we need to make sure that the SSL Context used to initiate the communication has been set with the Custom Identity Keystore and the Custom Trust keystore.
One convenient way to do this is to pass the Identity and Trust keystores as JVM options when a JVM process starts (on start of WebLogic or other web app server). JVM arguments can be passed in the server startup script (if present) or as command line argument.
The following is an example:
-Djavax.net.ssl.keyStore=D:\Path-to\identity.jks -Djavax.net.ssl.keyStoreType=JKS -Djavax.net.ssl.keyStorePassword=MyReallyComplexPassword -Djavax.net.ssl.trustStore=D:\Path-to\trust_keystore.jks -Djavax.net.ssl.trustStoreType=JKS -Djavax.net.ssl.trustStorePassword=MyTrustStorePassword
Where the value of javax.net.ssl.keyStore is what we called the Custom Identity Keystore and the value of javax.net.ssl.trustStore is what we called the Custom Trust Keystore.
Note: Another way to accomplish the same thing would be to load-and-set the Identity & Trust keystores directly in the client's code itself, before firing the request to the server. There are multiple examples on-line that explain how to do this.
Important: When writing a client that should communicate via Two-Way SSL make sure to never blindly trust all certificates. Many client libraries give you a boolean option TrustAllCerts that can be useful during development however if you leave it in production Two-Way SSL will NOT work. This is because by telling the SSL context to trust any certificate, the Server Certificate Exchange Key is not checked (since you trust it anyway) and thus the CertificateRequest from the server is ignored. The client will continue without sending its client certificates but, because the server expects the client to send one, the handshake process will end in failure.
I am using Spring-Boot Version 1.3.3.RELEASE. I'm trying to have my key-store and trust-store configured through application.yaml to set up two way SSL authentication.
There are two internal servers, one (call it A) using REST API to POST to the other (call it B, that's what I'm trying to configure).
Received our private key and cert (B's), merged it to a PKCS12 format and set it as the key-store (mykeystore.p12). Also received the other end private key and cert (A's), imported the cert only into a JKS format and set it as a trust-store (mytruststore.jks).
server:
port: 8443
ssl:
enabled: true
key-store: mykeystore.p12
key-store-password: mypass
key-store-type: PKCS12
client-auth: need
trust-store: mytruststore.jks
trust-store-password: mypass
trust-store-type: JKS
I wanted to test the connection, so I created a PKCS12 format cert from A's key and cert as well, and imported that into the browsers.
First the browser notifies me that the connection is not secure:
localhost:8443 uses an invalid security certificate.
The certificate is not trusted because the issuer certificate is unknown.
The server might not be sending the appropriate intermediate certificates.
An additional root certificate may need to be imported.
The certificate is only valid for *.somedomain
Error code: SEC_ERROR_UNKNOWN_ISSUER
But after accepting the risk, the client's cert validation fails (browser doesn't ask me which cert I want to use as client's cert):
An error occurred during a connection to some.domain. SSL peer cannot
verify your certificate. Error code: SSL_ERROR_BAD_CERT_ALERT
After that I created a self-signed certificate and key for test purposes, followed the steps above and with the self-signed certificate, it works. The browser asked which certificate I want to use as the client's cert, after selecting the only one I created, the SSL handshake was successful.
Tried to use the same PKCS12 format cert as key-store and trust-store, to make sure that the config is OK, but, again, it only worked with the self-signed cert.
My best guess I'm using localhost and B's cert's CN is *.somedomain. I created a test.somedomain entry in the hosts file and tried to use that to test B's cert, but the error still occurs.
Did I miss or misconfigured something, or how could I test if I correctly set up the two way SSL with the given certs?
I am trying to write a simple application to understand the basics of configuring authentication based on client and server certificates.
I have done everything as it is explained in jave ee 5, java ee 6 tutorials
http://docs.oracle.com/javaee/6/tutorial/doc/glien.html
Opened example from javaee tutorials hello basicauthorization (just simple servlet which can be accessed only after authentication) and then reconfigured it for client certificates instead of basic authorizations
Configured web.xml
Configured glassfish-web.xml
Generated client certificate
Imported client certificate so that the server would trust it.
The problem:
When I deploy my application, and follow the link, corresponding to the application, I get a message from glassfish server HTTP Status 400 - No client certificate chain in this request".
So, it seems, that the client (browser) doesn't send the certificate with the request
I tried adding the .cer certificate to Chrome, firefox, internet explorer and they are added (no error is displayed), but as you see that doesn't help.
So, the question is:
How to get the access to my application through the web browser having client .cer certificate?
You can debug ssl on the server-side by adding (somewhere in Glassfish) system properties:
-Djavax.net.debug=all
see this page for details.
You can also debug from the client perspective using openssl tool:
openssl s_client -connect host:port -debug -msg
you should see something like this:
...
Acceptable client certificate CA names
/C=PL/O=company/OU=xx/CN=host/emailAddress=email#example.com
/C=PL/O=company/OU=xx/CN=ca/emailAddress=email#example.com
---
SSL handshake has read 2536 bytes and written 116 bytes
...
your problem is probably related to bad truststore configuration on the server-side - server sends some Acceptable client certificate CA names (or no at all), but browser doesn't have anything to offer - it doesn't have any private key+certificate issued by acceptable ca.
I'm trying to set up a test environment for our application that uses X.509 client authentication over HTTPS in Tomcat 6.0. The servlet code is expecting to get a certificate chain as an array of X509Certificate objects using the javax.servlet.request.X509Certificate of the servlet request. However, this array only contains a single item (the client certificate), where I'm expecting it to have two (the client certificate and the root CA certificate that signed it).
Here's what I've done so far:
Generate a self-signed CA certificate using openssl.
Import the CA certificate as a trusted root certificate into a newly create Java keystore.
Configure the Tomcat HTTPS connector to require client authentication using the keystore created in step 2 as the truststore:
clientAuth="true"
truststoreFile="<path_to_truststore>"
Generate a new client certificate using openssl and sign it with the CA certificate.
Start Tomcat.
Install the client certificate in Chrome and navigate to my server's homepage. Stepping through the code in debug, I can see that the array returned as the javax.servlet.request.X509Certificate attribute only has the client certificate.
I know that Tomcat is picking up the root CA certificate from the truststore because when I delete it from the truststore, I get an SSL connection error. It's just not making it into the servlet request like the documentation says it should. Am I missing any additional configuration here? Perhaps Tomcat (or Java or JSSE) is expecting some additional X509 V3 extensions or something?
Any help is appreciated!
EDIT
Looks like my setup is legit, and this falls into the category of unusual but expected behavior due to a simplified test environment. In an enterprise scenario it's unlikely that the root certificate authority is going to be directly signing client certificates for individual users. Clearly when this code was written and tested, there was at least one intermediate CA involved in the trust chain.
What your are seeing is what is expected: Chrome is not sending the CA.
During the TSL Handshake when authenticating the client, the server will send a list of acceptable CAs as part of its CertificateRequest Message (RFC), the browser will then present a Certificate signed by one of these CAs.
ADD
btw, a great way of debugging an SSL connection client side is to use the fantastic openssl tools
openssl s_client -connect ssl.server.com:443
or for SSLV3 only servers
openssl s_client -connect ssl.server.com:443 -ssl3
This will print (among other things) the list of acceptable CAs.
To debug the server side add this to the JVM command line -Djavax.net.debug=ssl
The identity keystore should contain the cert signed by the CA ; not the self-signed cert. The CA root should be in the truststore.
Also, what is the purpose of step 4 ?