Background:
I have a Scala
(with AKKA-http
) webserver, that is able to talk to instances of itself (de-centralised model). I recently upgraded the server to use SSL
and https
.
I have run into a problem with the communications between two servers, related to SSL
certificates:
java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Thoughts:
A quick search for the exception lead me to this post. I had seen the keytool
command at various points when I was researching SSL
in Scala
/Java
so I know I'm on the right track.
However, the service I am writing needs to be end-user friendly. The answers in this post require a lot of user setup. I would like the user to have to do as little as possible in the way of setting this up and would like to have my server handle this itself.
The model here was you share your domain name and serverID with your friends, and they can register with you. The post mentioned would require you to also share your SSL certificate and manually add it on your machine for each server you register with.
I think I need to exchange the SSL
certificate at some point during the registration handshake?
Handshake Process:
Currently the handshake process is as follows:
- User A create a
RegistrationRequest(serverID, serverIP, alias)
to User B, and a database entry for User B - User B receives the request, creates an entry in its database for User A
- User B (the actual end user) clicks "Accept" on the front-end for User A's request
- User B send a
RegistrationAccept
message to user A - User A receives the accept request, and updates the database to reflect it is accepted
- The
chatter
service is started on both ends
I was thinking I would do the handshake with http
, inserting the SSL
certificate into the RegistrationRequest
object, and upgrade the connection to https
when the certificate was exchanged, but this is a problem. Each webserver binds to port 8080
. I would have to re-bind the entire socket each time which will work for just 1 to 1 peers, but not 1 to many.
Any suggestions on the correct approach to solving this?
Thanks in advance!
UPDATE:
I have come quite far with this project and integrated a lot of features into the backend. However, the system is meant to be security focused so if I continue this way, SSL
is a must.
I didn't really want to re-write the entire backend, but assuming I did, are websockets
what I want here instead of my current approach?
UPDATE 2:
Seems there are two approaches, neither of which I'm completely sure about (from a security perspective).
Approach 1:I ship the software with a single RootCA
certificate, that I use to generate the SSL
certificates. This seems like it might have security implications if someone gets hold of the RootCA
and generates their own certificates.
Approach 2:I create 2 sockets, one for http
(port 8080) and another for https
(port 8443).
The http
socket exposes routes ONLY for authenticating credentials (and providing a token) and for adding a certificate to the truststore
(ONLY if the token is valid).
Then any requests on the https
routes will be rejected if the certificate is not present or the token is invalid, but will work for registered users.
Again, seems to have security implications sharing certificate over http
, but seems better than shipping with RootCA
as it at least has authentication wrapped around it (or am I wrong?)