B4J Question Certificate pinning for websockets

Chris2

Active Member
Licensed User
Longtime User
Is it possible to use code similar to this:
to add certificate pinning to a wss websocket client connection and remove the need to use 'accept all certificates' when a self-signed certificate is in use at the server end?

More details:
I have a jRDC2 based server which also includes websocket messaging. The server is using a self-signed certificate wth the keystore loaded via:
jRDC2 ssl keystore:
Private Sub ConfigureSSL (sslPort As Int)
    Dim ssl As SslConfiguration
    ssl.Initialize
    ssl.SetKeyStorePath("keyStorePath", "keystoreName") 'path to keystore file
    ssl.KeyStorePassword = "pw"
    ssl.KeyManagerPassword = "pw"
    srvr.SetSslConfiguration(ssl, sslPort)
    'add filter to redirect all traffic from http to https (optional)
    srvr.AddFilter("/*", "HttpsFilter", False)
End Sub
I have client apps which connect to the server via https and websocket. Until now I've always set both to 'Accept all certificates', using HU2_ACCEPTALL conditional symbol for the https, and this code for the websocket connection.

Just as a learning process I thought I'd look into using certificate pinning instead of just accepting all certificates.
Using @Erel's code for the SSLContext-Kickstart SDK worked striaght out of the box for the https connection. Loading the same keystore into the client that's in the server allowed me to remove the HU2_ACCEPTALL condition.

But the websocket connection still needs the Accept All code to connect. So I'm wondering if anyone can provide me with something similar to allow me to 'pin' the keystore to the websocket client too?

Many thanks.
 
Solution
You are correct!

While the main purpose for the linked post is different, it does allow to use a custom trusted store with OkHttp.
To complete your question, this will make the WebsocketClient work:
B4X:
'WebsocketClient and probably other network related methods
SetSystemProperty("javax.net.ssl.trustStore", "C:\Users\H\Downloads\bxb.p12")
SetSystemProperty("javax.net.ssl.trustStorePassword", "123456")
'OkHttpUtils2:
SetSSLFactory("C:\Users\H\Downloads\bxb.p12", "", "123456")

Erel

B4X founder
Staff member
Licensed User
Longtime User
There is a confusion here. The client certificates feature is not related to the self signed server certificate. Client certificate is a method that allows the server to authenticate the client.

You need to create a truststore based on the self signed certificate and configure the client to use it:
B4X:
    SetSystemProperty("javax.net.ssl.trustStore", "C:\Users\H\Downloads\bxb.p12")
    SetSystemProperty("javax.net.ssl.trustStorePassword", "123456")

It is not trivial and my attempt to demonstrate it didn't succeed.
 
Upvote 0

Chris2

Active Member
Licensed User
Longtime User
There is a confusion here.
That's more than likely :).

I was pointed to the OkHttpUtils2 SSLContext-Kickstart library by your post here:
About certificate pinning.........
The only case where it can be important is if you are using a non-trusted certificate and you don't want to enable the "trust all" option.
It should be possible to implement it using Kickstart: https://www.b4x.com/android/forum/t...tputils2-sslcontext-kickstart.132549/#content

I can't claim to understand the SSLContext-Kickstart code at all and I was surprised when it worked, but in my client/server apps simply removing the HU2_ACCEPTALL conditional symbol in the client and calling the SetSSLFactory sub instead (loading the same self-signed keystore that the server is using) allowed the client to connect to the server successfully.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
You are correct!

While the main purpose for the linked post is different, it does allow to use a custom trusted store with OkHttp.
To complete your question, this will make the WebsocketClient work:
B4X:
'WebsocketClient and probably other network related methods
SetSystemProperty("javax.net.ssl.trustStore", "C:\Users\H\Downloads\bxb.p12")
SetSystemProperty("javax.net.ssl.trustStorePassword", "123456")
'OkHttpUtils2:
SetSSLFactory("C:\Users\H\Downloads\bxb.p12", "", "123456")
 
Upvote 0
Solution

Chris2

Active Member
Licensed User
Longtime User
Thanks @Erel!

Two follow up questions please:
1. The WebsocketClient now returns an error :
B4X:
javax.net.ssl.SSLHandshakeException: No name matching localhost found
I understand (I think) that this is because my self-signed keystore does not have the correct host name ('localhost' in this case), so I could correct it by recreating the keystore with the correct hotstname.
But the OkHttpUtils2 connection doesn't complain about the hostname, so can the Websocket be made to ignore the hostname too?

2. Does the SetSystemProperty method overide the truststore for the individual app only, or system wide?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
2. Does the SetSystemProperty method overide the truststore for the individual app only, or system wide?
Individual app.

A simple solution, which has several advantages, is to add an entry in the hosts file and create a "fake" domain that points to localhost. And make the certificate match this domain.
 
Upvote 0
Top