0

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());

0 Answers0