ttyd uses client cert
Bug: 363235314
Test: terminal app can show ttyd page, but the others cannot access to
the page
Change-Id: I60e4249f0170caa54e6c6777e9fc03cff176541c
diff --git a/android/TerminalApp/Android.bp b/android/TerminalApp/Android.bp
index d91af2f..932ca76 100644
--- a/android/TerminalApp/Android.bp
+++ b/android/TerminalApp/Android.bp
@@ -9,6 +9,7 @@
"java/**/*.kt",
],
resource_dirs: ["res"],
+ asset_dirs: ["assets"],
static_libs: [
"vm_launcher_lib",
"androidx-constraintlayout_constraintlayout",
diff --git a/android/TerminalApp/assets/client.p12 b/android/TerminalApp/assets/client.p12
new file mode 100644
index 0000000..f1f5820
--- /dev/null
+++ b/android/TerminalApp/assets/client.p12
Binary files differ
diff --git a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
index 1fabf8d..3aca929 100644
--- a/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
+++ b/android/TerminalApp/java/com/android/virtualization/terminal/MainActivity.java
@@ -19,6 +19,7 @@
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
+import android.net.http.SslError;
import android.os.Bundle;
import android.system.ErrnoException;
import android.system.Os;
@@ -27,6 +28,8 @@
import android.view.MenuItem;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
+import android.webkit.ClientCertRequest;
+import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
@@ -44,11 +47,17 @@
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
public class MainActivity extends AppCompatActivity
implements VmLauncherServices.VmLauncherServiceCallback,
@@ -57,6 +66,8 @@
private static final String TAG = "VmTerminalApp";
private static final String VM_ADDR = "192.168.0.2";
private static final int TTYD_PORT = 7681;
+ private X509Certificate[] mCertificates;
+ private PrivateKey mPrivateKey;
private WebView mWebView;
private AccessibilityManager mAccessibilityManager;
@@ -92,6 +103,7 @@
mAccessibilityManager.addTouchExplorationStateChangeListener(this);
connectToTerminalService();
+ readClientCertificate();
}
private URL getTerminalServiceUrl() {
@@ -100,13 +112,35 @@
String query = needsAccessibility ? "?screenReaderMode=true" : "";
try {
- return new URL("http", VM_ADDR, TTYD_PORT, file + query);
+ return new URL("https", VM_ADDR, TTYD_PORT, file + query);
} catch (MalformedURLException e) {
// this cannot happen
return null;
}
}
+ private void readClientCertificate() {
+ // TODO(b/363235314): instead of using the key in asset, it should be generated in runtime
+ // and then provisioned in the vm via virtio-fs
+ try (InputStream keystoreFileStream =
+ getClass().getResourceAsStream("/assets/client.p12")) {
+ KeyStore keyStore = KeyStore.getInstance("PKCS12");
+ String password = "1234";
+ String alias = "1";
+
+ keyStore.load(keystoreFileStream, password != null ? password.toCharArray() : null);
+ Key key = keyStore.getKey(alias, password.toCharArray());
+ if (key instanceof PrivateKey) {
+ mPrivateKey = (PrivateKey) key;
+ Certificate cert = keyStore.getCertificate(alias);
+ mCertificates = new X509Certificate[1];
+ mCertificates[0] = (X509Certificate) cert;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage());
+ }
+ }
+
private void connectToTerminalService() {
Log.i(TAG, "URL=" + getTerminalServiceUrl().toString());
mWebView.setWebViewClient(
@@ -146,6 +180,23 @@
view.setVisibility(View.VISIBLE);
}
}
+
+ @Override
+ public void onReceivedClientCertRequest(
+ WebView view, ClientCertRequest request) {
+ if (mPrivateKey != null && mCertificates != null) {
+ request.proceed(mPrivateKey, mCertificates);
+ return;
+ }
+ super.onReceivedClientCertRequest(view, request);
+ }
+
+ @Override
+ public void onReceivedSslError(
+ WebView view, SslErrorHandler handler, SslError error) {
+ // ttyd uses self-signed certificate
+ handler.proceed();
+ }
});
new Thread(
() -> {