I’m trying to connect to a WebSocket server using OkHttp in an Android application. The server uses a self-signed certificate. While I can successfully connect to the server using wscat from the command line, my Android app fails to connect.
Here’s my server setup using Vert.x and the client code in Android:
Server Code (Vert.x)
import io.vertx.core.Vertx;
public class App {
public String getGreeting() {
return "Hello World!";
}
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new VertxSocket());
}
}
VertxSocket.java:
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.net.PfxOptions;
import io.vertx.core.json.JsonObject;
import io.vertx.core.eventbus.EventBus;
import java.nio.file.Path;
import java.nio.file.Paths;
public class VertxSocket extends AbstractVerticle {
@Override
public void start() {
Path path = Paths.get("C:\Users\Jaydeep\Desktop\key\keystore.p12");
String keystorePath = path.toAbsolutePath().toString();
System.out.println(keystorePath);
HttpServerOptions options = new HttpServerOptions()
.setSsl(true)
.setPfxKeyCertOptions(new PfxOptions()
.setPath(keystorePath)
.setPassword("123"));
HttpServer server = vertx.createHttpServer(options);
EventBus eventBus = vertx.eventBus();
server.webSocketHandler(webSocket -> {
System.out.println("Connected!");
// Handle incoming messages
webSocket.handler(data -> {
System.out.println(data);
JsonObject message = data.toJsonObject();
String event = message.getString("event");
JsonObject payload = message.getJsonObject("payload");
eventBus.publish(event, payload);
webSocket.writeFinalTextFrame(data.toString());
});
webSocket.closeHandler(v -> {
System.out.println("Disconnected!");
});
webSocket.exceptionHandler(throwable -> {
System.out.println("Error: " + throwable.getMessage());
});
}).listen(8080, res -> {
if (res.succeeded()) {
System.out.println("Server is now listening on port 8080!");
} else {
System.out.println("Failed to bind!");
res.cause().printStackTrace();
}
});
// Register handlers for the events on the Event Bus
eventBus.consumer("OnPawnMove", message -> {
JsonObject payload = (JsonObject) message.body();
handlePawnMove(payload);
});
eventBus.consumer("OnDiceRoll", message -> {
JsonObject payload = (JsonObject) message.body();
handleDiceRoll(payload);
});
}
private void handlePawnMove(JsonObject payload) {
System.out.println("Pawn moved to: " + payload.encode());
}
private void handleDiceRoll(JsonObject payload) {
System.out.println("Dice rolled: " + payload.encode());
}
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new VertxSocket());
}
}
Android Client Code
MainActivity.java:
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
WebSocketHelper webSocketHelper = new WebSocketHelper(this);
webSocketHelper.connectWebSocket();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Error: " + e.toString());
}
}
}
WebSocketHelper.java:
package com.example.imagemovement.sslconnect;
import android.content.Context;
import android.util.Log;
import com.example.imagemovement.R;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class WebSocketHelper {
private static final String TAG ="WebSocketHelper" ;
private Context context;
public WebSocketHelper(Context context) {
this.context = context;
}
public void connectWebSocket() {
try {
// Load CA certificate
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = context.getResources().openRawResource(R.raw.ca);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keyInputStream = context.getResources().openRawResource(R.raw.keystore);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
// Load client certificate and key
InputStream crtInput = context.getResources().openRawResource(R.raw.crt);
Certificate crt = cf.generateCertificate(crtInput);
crtInput.close();
InputStream keyInput = context.getResources().openRawResource(R.raw.key);
// Assuming the key is in PKCS#8 format
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, "123".toCharArray()); // Use the password you used to generate the key
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// Create OkHttpClient and configure it to use the SSLContext
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0])
.build();
Request request = new Request.Builder().url("wss://www.wslphone.com:8080").build();
WebSocketListener listener = new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("hi");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
Log.d(TAG,"Received: " + text);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
Log.d(TAG,"Received bytes: " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
Log.d(TAG,"Closing: " + code + " / " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
t.printStackTrace();
Log.d(TAG,t.toString());
}
};
WebSocket ws = client.newWebSocket(request, listener);
client.dispatcher().executorService().shutdown();
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "WebsocktHelper: " + e.toString());
}
}
}
I have used same certificate and key which I used to generate keystore.p12 file In the Android Project However I am getting this error:
java.net.UnknownHostException: Unable to resolve host “www.wslphone.com”: No address associated with hostname
I have used www.wslphone.com as my domain while creating self signed certificate
I have able to connect to server using wscat:
C:UsersJaydeep>wscat -c wss://www.wslphone.com:8080 –key C:UsersJaydeepDesktopkeykey.key –cert C:UsersJaydeepDesktopkeycrt.crt –ca C:UsersJaydeepDesktopkeyca.pem
Connected (press CTRL+C to quit)
hi
Disconnected (code: 1006, reason: “”)
I am trying to connect to a server using wss:
- Server is created uisng vertx java, for wss I have used self signed certificate.
- I am trying to connect my android app using Okhttps3 howere I am unable to connect to ther server and I am getting this error:java.net.UnknownHostException: Unable to resolve host “www.wslphone.com”: No address associated with hostname
I am expecting to connect to my server using self signed certificate from my android app.
I am able to connect with just ws but my goal is to connect using wss