Android: Add TLS connection test and FIPS error callback to example app

pull/355/head
Chris Conlon 2026-04-08 11:03:09 -06:00
parent 799b277531
commit c58a0bd747
2 changed files with 143 additions and 30 deletions

View File

@ -24,31 +24,75 @@ package com.example.wolfssl;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.wolfssl.WolfSSL;
import com.wolfssl.WolfSSLException;
import com.wolfssl.WolfSSLFIPSErrorCallback;
import com.wolfssl.provider.jsse.WolfSSLProvider;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.Security;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class MainActivity extends AppCompatActivity {
private View.OnClickListener buttonListener = new View.OnClickListener() {
private static final String TAG = "wolfSSL FIPS";
/**
* Custom FIPS error callback that logs directly to Android logcat via
* android.util.Log. This ensures FIPS error details and the expected
* verifyCore hash are always visible in logcat, regardless of whether
* wolfJSSE debug logging is enabled.
*
* The expected verifyCore hash can also be seen in the wolfJSSE
* debug logs by setting the "wolfjsse.debug" system property to "true"
* before creating the provider, ie:
*
* System.setProperty("wolfjsse.debug", "true");
*/
private static class FIPSErrorCallback
implements WolfSSLFIPSErrorCallback {
@Override
public void errorCallback(
int ok, int err, String hash) {
if (ok == 1) {
Log.d(TAG, "FIPS callback: ok = " + ok + ", err = " + err);
Log.d(TAG, "Expected verifyCore hash: " + hash);
}
else {
Log.e(TAG, "FIPS error callback: ok = " + ok + ", err = " + err);
Log.e(TAG, "Expected verifyCore hash: " + hash);
if (err == -203) {
Log.e(TAG,
"FIPS in-core integrity check failed. Copy the " +
"above hash into WOLFCRYPT_FIPS_CORE_HASH_VALUE in " +
"CMakeLists.txt and rebuild.");
}
}
}
}
private View.OnClickListener buttonListener =
new View.OnClickListener() {
@Override
public void onClick(View v) {
TextView tv = (TextView) findViewById(R.id.sample_text);
try {
testFindProvider(tv);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
testTLSConnection();
}
}).start();
}
};
@ -79,25 +123,94 @@ public class MainActivity extends AppCompatActivity {
setDisplayText("wolfSSL JNI Android Studio Example App\n");
}
public void testFindProvider(TextView tv)
throws NoSuchProviderException, NoSuchAlgorithmException,
WolfSSLException {
private void testTLSConnection()
{
String host = "www.wolfssl.com";
int port = 443;
SSLSocket sock = null;
WolfSSL.loadLibrary();
setDisplayText("wolfSSL JSSE TLS Connection Test\n");
appendDisplayText("==================================\n\n");
/* create new SSLEngine */
Security.insertProviderAt(new WolfSSLProvider(), 1);
try {
/* Register wolfJSSE provider if not already registered.
* This loads native libraries, registers the default
* FIPS callback, and calls wolfSSL_Init() internally. */
if (Security.getProvider("wolfJSSE") == null) {
Security.insertProviderAt(new WolfSSLProvider(), 1);
Provider p = Security.getProvider("wolfJSSE");
if (p == null) {
appendDisplayText("Unable to find wolfJSSE provider\n");
/* Register custom FIPS error callback after creating the
* provider. The provider registers its own callback internally,
* so custom one must be set after. Only one callback can be
* registered at a time. */
WolfSSL.setFIPSCb(new FIPSErrorCallback());
}
if (Security.getProvider("wolfJSSE") == null) {
appendDisplayText("ERROR: wolfJSSE provider not found\n");
return;
}
appendDisplayText("Registered wolfJSSE provider\n");
/* Create SSLContext and SSLSocket */
SSLContext ctx = SSLContext.getInstance("TLS", "wolfJSSE");
ctx.init(null, null, null);
SSLSocketFactory sf = ctx.getSocketFactory();
appendDisplayText("Connecting to " + host + ":" + port + "\n");
sock = (SSLSocket) sf.createSocket(host, port);
sock.startHandshake();
appendDisplayText("TLS handshake complete\n");
appendDisplayText("Protocol: " +
sock.getSession().getProtocol() + "\n");
appendDisplayText("Cipher: " +
sock.getSession().getCipherSuite() + "\n\n");
/* Send HTTP GET request */
String httpGet = "GET / HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n";
OutputStream os = sock.getOutputStream();
os.write(httpGet.getBytes());
os.flush();
appendDisplayText("Sent HTTP GET request\n\n");
/* Read response (first few lines) */
InputStream is = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line;
int lineCount = 0;
int maxLines = 15;
appendDisplayText("--- Response ---\n");
while ((line = br.readLine()) != null && lineCount < maxLines) {
appendDisplayText(line + "\n");
lineCount++;
}
if (lineCount >= maxLines) {
appendDisplayText("...\n");
}
appendDisplayText("--- End ---\n\n");
} catch (Exception e) {
appendDisplayText("ERROR: " + e.getMessage() + "\n");
e.printStackTrace();
} finally {
if (sock != null) {
try {
sock.close();
appendDisplayText("Socket closed successfully\n");
} catch (Exception e) {
appendDisplayText("Error closing socket: " +
e.getMessage() + "\n");
}
}
}
else {
appendDisplayText("Successfully found wolfJSSE provider\n");
}
appendDisplayText("\n");
appendDisplayText("For more detailed example, see:\n");
appendDisplayText("github.com/wolfssl/wolfssl-examples\n");
}
}
}

View File

@ -10,7 +10,7 @@
android:id="@+id/button"
android:layout_width="320dp"
android:layout_height="wrap_content"
android:text="Test Provider Lookup"
android:text="TLS Connection Test"
app:layout_constraintBottom_toTopOf="@+id/sample_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"