Self-Signed Certificates in Spring-Boot - spring-boot

I'm trying to get a Spring-Boot server up and running, which provides some security via SSL. I followed steps 1 and 2 of this guide to get a self-signed certificate and am able to access my site via https. The application.properties looks like this:
server.port=8443
server.ssl.keyStore=classpath:keystore.p12
server.ssl.keyStorePassword=youd_want_to_know
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=hs
keystore.p12 was generated with
$ keytool -genkey -alias hs -storetype PKCS12 \
-keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
Except for the password I didn't enter anything, all fields are "Unknown".
However, the lock in the browser isn't green. The detail message says
There are issues with the site's certificate chain (net::ERR_CERT_AUTHORITY_INVALID).
The plus-side:
Secure TLS connection
The connection to this site is using a strong protocol version and cipher suite.
Secure Resources
All resources on this page are served securely.
I guess in plain text it means that the data is transported securely, but the browser isn't fully happy with the certificate in terms of it can't track the authenticity. Therefore, I understand that this isn't worthy for production (and for now it doesn't need to be).
But, is it safe and secure for me since I own the server and know that I created the self-signed certificate myself? Or are there ways to turn this into a certificate that the browser is happy with? What do I need to do to make that work and what would the Sprint-Boot configuration look like?

Thats how the browser is supposed to behave. As long as you (or rather, browsers you or your organization owns) are the only consumers of your website, you are fine. But once you want to on-board other consumers you might need to get your certificate signed by a certificate provider

In this case the communication between browser and server is still vulnerable to man-in-the-middle attack, so this not really "secure & safe"

In a Nutshell,
Using a self signed certificate is completely unsafe unless
you control every machine between you and the server
OR
you check that the keys in the certificate are what you expect them
to be.
Only advantage is; it will block passive attacks (the attacker observes the data but does not alter it in any way) regardless of whether the CA certificate was issued by a mainstream CA or not.
Take a look here https://security.stackexchange.com/a/8112

Related

OkHttp client certificate without intermediaries

I'm trying to use okhttp to authenticate to a server.
With curl it would be done this way:
curl \
--cert certificate.cer \
--key private-key.pkcs8 \
"https://some-url"
Unfortunately, okhttp-tls appears to always expect a chain of certificates in addition to the held certificate, which isn't something I have.
heldCertificate expects the chain of certificates, in addition to the clientCertificate, contrary to the example provided in the reame:
HandshakeCertificates clientCertificates = new HandshakeCertificates.Builder()
.addTrustedCertificate(rootCertificate.certificate())
.heldCertificate(clientCertificate) // <--------------------
.build();
How can I use okhttp with a single certificate and my private key?
heldCertificates expects a chain of intermediates that may exist between the client certificate (matching the private key) and up to but not including the root CA that the server is known to trust. So this could be left out if no other certificates are required.
See https://square.github.io/okhttp/4.x/okhttp-tls/okhttp3.tls/-handshake-certificates/-builder/held-certificate/
Configure the certificate chain to use when being authenticated. The
first certificate is the held certificate, further certificates are
included in the handshake so the peer can build a trusted path to a
trusted root certificate.
The chain should include all intermediate certificates but does not
need the root certificate that we expect to be known by the remote
peer. The peer already has that certificate so transmitting it is
unnecessary.
Here are some examples for using a self-signed certificate if known to be trusted already by the server, and also for switching the key used based on the host being connected to. You will need to adapt these based on your exact setup, but they should give you a starting point to test with.
https://github.com/square/okhttp/pull/6470/files

What steps should I take to validate a SSL Certificate manually as browsers do?

How do browsers like Chrome check SSL Certificate?
IS there any online databases or websites that they use?
What steps are taken by browsers to validate a SSL certificate?
Am I able to do it manually without using browser?
How do browsers like Chrome check SSL Certificate?
The certificate and chain is send by the server during the SSL handshake. The browser will create the trust chain based on the certificate issuer, provided chain certificates and the local root certificates. It will check expiration and purpose of the certificate and also check the subject alternative names (and maybe subject too) to make sure that the certificate is actually issued for the domain in the URL. It might also do some checks for certificate revocation.
For details see SSL Certificate framework 101: How does the browser actually verify the validity of a given server certificate? and How Do Browsers Handle Revoked SSL/TLS Certificates?.
I there any online database or websites that they use?
Not really. The necessary trust store is local. They might check revocation though against some online resource. See Is Certificate validation done completely local?.
Am I able to do it manually without using browser?
Sure, what the browser does could in theory be replicated manually. You can for example access the site and get the leaf and intermediate certificates with openssl s_client -showcerts .... You can then use openssl verify to verify the certificate chain, see also Verify a certificate chain using openssl verify. Then you need to look at the leaf certificate with openssl x509 -text ... to check purpose, expiration and the subject. Revocation is tricky but could be done with the help of openssl crl and openssl ocsp, although this does not really reflect what browsers do.
The official algorithm for validating any SSL/TLS certificate is defined by PKIX as modified by OCSP. For TLS nowadays the OCSP token is often transported by 'stapling' in the TLS handshake instead of by a separate connection, which requires several other RFCs, but that only affects transport, not the actual validation by the relier. For HTTPS specifically, the client must also check server identity aka 'hostname' as defined by rfc2818.
In practice, browsers may vary some. Chrome mostly uses a google-determined scheme to 'push' revocation data they select, but this has changed from time to time. Firefox, last I heard, used their own 'one-CRL' scheme. Also, although the standard and traditional practice was to check hostname against SAN if present and otherwise fall back to Subject.CN, Chrome since a few years ago requires SAN and never uses CN; you can find dozens of Qs on several stacks about "my selfsigned or otherwise DIY cert not from a real CA stopped working on Chrome".
If by 'do it manually' you really mean manually, that will be a lot of work. If you mean with tools other than a browser offline, somewhat easier; OpenSSL (if installed) can do most of this, although you need more options than shown in Steffen's link to get it right.
If you mean with tools other than a browser online, absolutely. The WWW has become extremely popular in recent decades, and there are zillions of programs and libraries for accessing it, nearly all of them including HTTPS (although two decades ago that was less common), which includes validating the certificate -- at least by default; many have options to disable, bypass, or override validation. There are standalone tools like curl and wget -- or openssl s_client can do the SSL/TLS and certificate part without doing HTTP on top. There are innumerable libraries and middlewares like ssl in python (or requests using it), tls in nodejs, (older) HttpsURLConnection and (newer) java.net.http in Java as well as third-parties like Apache HttpComponents; I'm sure there are counterparts for perl and dotnet although I'm not familiar with them. As well as powershell, which is fuzzy on the program/library distinction.

Is a world known CA certificate compulsory for a https site?

I want my site to be secure using HTTPS protocols. I managed to make a self-signed key to be trustedCertEntry as I made my own CA certificate, with different CN, which I used to sign my own private certificate.
It works smooth testing it with openssl with something like:
openssl s_client -connect www.mydomain.com:80 -tls1 -state
Thus, browser doesn't report a certificate self-signed error, as it sees a different CA.
But I get a SEC_ERROR_UNKNOWN_ISSUER error. Still it seems logical to me as nobody knows me as a CA. It is supposed to work if user adds exception for me.
I thought this trick was acceptable and it was like many https compliant sites were working, as you may visit a unknown site and you want to encrypt communications from 3rd party watchers but trust that page.
After trying to get a clear response for it, beyond coding that I will find resources, my question is:
If I want to have a site, for which the users don't have to add an exception in the first visit, do I have to get a certificate from a "world-known" CA? Or am I missing a solution for self-signing my certificate with my own CA certificate?
Technically speaking, the answer is: Yes, you will have to get a certificate from a CA that is trusted by your users' browsers via a chain of intermediary CA's that ends at an inherently trusted root CA. The accepted answer to this question explains how it works: SSL Certificate framework 101: How does the browser actually verify the validity of a given server certificate?
Having said that, if your "only" concern is to provide encrypted connections, you might be able to leverage the Let's Encrypt CA, which provides free certificates for that purpose. Those certificates will be only domain-validated, which provides a weaker kind of assurance of identity than, for example, an Extended Validation Certificate.
Depending on the browser used, there will be minimal difference in user experience between DV and EV certificates. For Safari, the user will see a grey padlock in the address bar for the lower assurance DV-backed sites, like this:
and a green padlock when higher identity assurance is provided, like this:
Whether the former is good enough for you (or your customers) depends on your situation.
In case you want to understand what "inherently trusted" actually means for web browsers, see this blog post: Who your browser trusts, and how to control it.

How to configure Tomcat (in Spring Boot) to provide full certificate chain with SSL connections? (currently working with Chromium, not with Firefox)

I have the following issue: I have a domain that hosts a) a website on port 443 (Apache) and b) a web app with Spring Boot (Tomcat) on port 8443. Both are using the same certificates. For Tomcat I generated a keystore that consists of the private key/certificate, intermediate and root certificate. Visiting the website is not an issue at all.
Now, when I visit the webapp from e.g. Chromium or from my smartphone I can access it and https works just fine (certificate is trusted and I can view the certificate chain). If I instead try opening it in Firefox or use openssl s_client -connect domain.com:8443 the connection is not secured and only my certificate, but neither the intermediate and nor the root certificate are provided.
Now I don't understand how that happens, whether maybe Chrome recognizes the certificate chain from the issuer field of the certificate or asks the app server to provide further parts of the chain, and Firefox/openssl do not.
Any hint about how to make this running would be greatly appreciated!
BR Johannes
BTW about the keystore creation: I created an empty keystore, added the root, then the intermediate and then my certificate + key.
Seems I made a mistake on how to create the keystore, just importing the certificate chain and the key pair wasn't enough. I had to append the certificates of the chain to my certificate (using KeyStoreExplorer or as described in this answer.
How it came that Chromium accepted the certificate anyway is still a mistery to me, though.

Implementing 2-way SSL authentication with WebSphere MQ

I use a Java client using JMS/JNDI. The connection is working when using one-way SSL authentication SSLCAUTH(OPTIONAL). The first step I did is to export the public certificate of the client:
keytool -export -keystore keystore -storepass storepass -alias CLIENT -file client.cer
Then I added this certificate to the MQ key repository.
gsk7cmd -cert -add -db keydb.kdb -pw password -label ibmwebspheremqclient -file client.cer -format binary
And I finally switched to SSLCAUTH(REQUIRED) mode.
I get the following error log. The message is pretty clear, it can't find my client certificate. I read that my client certificate should have a label ibmwebspheremq<client_user_id>. What is this user id since I am connecting via Java?
AMQ9637: Channel is lacking a certificate.
As per the Technote Specifying the userid in the SSL certificate label for an MQ client the Java and JMS clients do not find their certificate based on the label.
What is often the problem is a mis-match between the trust store and the key store. I have seen two problems fairly commonly.
The application specifies a trust store but not a keystore. This works great for anonymous (one-way) SSL but not for mutual authenticated SSL. The app must specify both key store and trust store for mutual auth.
Sometimes the app specifies a trust store file but the private certs are in the key store. Or the app specifies the same file for both trust store and the key store and the personal certs are actually in a separate trust store file.
Does either of these solve the problem? If not, please update the question with a keytool -cert -list for both the key store and the trust store and the part of the command line or code that sets up the keystore/truststore.

Resources