Trying to connect an android Java App to an API secured with mTLS that uses self-signed certificates
I tried the following code. The TLS part is working since when disabling the certificate authentication on server side the get request goes through with no problem. However when re-enabling I get the following error:
"error:1000045c:SSL routines:OPENSSL_internal:TLSV1_ALERT_CERTIFICATE_REQUIRED (external/boringssl/src/ssl/tls_record.cc:594 0xb4000074d73e2188:0x00000001)". Any ideas? Thanks!
OkHttpClient client;
// Load the client private key and public key from the "client.privkey" and "client.pubkey" files
PrivateKey privKey = null;
PublicKey pubKey = null;
Resources res = getReactApplicationContext().getResources();
try {
// Open the "client.privkey" and "client.pubkey" files as InputStreams
InputStream privKeyStream = res.openRawResource(R.raw.privkey);
InputStream pubKeyStream = res.openRawResource(R.raw.client);
// Read the private key
String privKeyStr = readInputStream(privKeyStream);
privKey = getPrivateKeyFromString(privKeyStr);
// Read the public key
String pubKeyStr = readInputStream(pubKeyStream);
pubKey = getPublicKeyFromString(pubKeyStr);
} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException e) {
// Handle exceptions
}
// Load the self-signed certificate from the R.raw resources
InputStream caInput = getReactApplicationContext().getResources().openRawResource(R.raw.cacert);
Certificate ca;
try {
// Generate a Certificate object from the certificate file
CertificateFactory cf = CertificateFactory.getInstance("X.509");
ca = cf.generateCertificate(caInput);
} catch (CertificateException e) {
throw new RuntimeException("Failed to generate certificate", e);
} finally {
try {
caInput.close();
} catch (IOException e) {
// Ignore
}
}
// Create a KeyStore containing the self-signed certificate
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
keyStore.setKeyEntry("client", privKey, null, new Certificate[] { ca });
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
throw new RuntimeException("Failed to create key store", e);
}
// Create a TrustManagerFactory that trusts the self-signed certificate
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf;
try {
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
} catch (NoSuchAlgorithmException | KeyStoreException e) {
throw new RuntimeException("Failed to create TrustManagerFactory", e);
}
// Create an SSLContext that uses the TrustManagerFactory
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException("Failed to create SSLContext", e);
}
// Create an OkHttpClient that uses the SSLContext
client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0])
.build();
Log.d(TAG, "Requesting from url: " + API_URL);
Request request = new Request.Builder()
.url(API_URL)
.build();
//set hostname verifier
client = client.newBuilder().hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}).build();
// Encode the client public key to a base64 string
String pubKeyStr = pubKey.toString();
String finalPubKeyStr = pubKeyStr;
client = client.newBuilder().addInterceptor(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Client-Public-Key", finalPubKeyStr)
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
}).build();
//set client certificate authentication
client = client.newBuilder().sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tmf.getTrustManagers()[0]).build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new IOException("Unexpected response code: " + response.code());
}
Log.d(TAG, "Response: " + response.body().string());