[adbwifi] Add A_STLS command.

This command will be sent by adbd to notify the client that the
connection will be over TLS.

When client connects, it will send the CNXN packet, as usual. If the
server connection has TLS enabled, it will send the A_STLS packet
(regardless of whether auth is required). At this point, the client's
only valid response is to send a A_STLS packet. Once both sides have
exchanged the A_STLS packet, both will start the TLS handshake.

If auth is required, then the client will receive a CertificateRequest
with a list of known public keys (SHA256 hash) that it can use in its
certificate. Otherwise, the list will be empty and the client can assume
that either any key will work, or none will work.

If the handshake was successful, the server will send the CNXN packet
and the usual adb protocol is resumed over TLS. If the handshake failed,
both sides will disconnect, as there's no point to retry because the
server's known keys have already been communicated.

Bug: 111434128

Test: WIP; will add to adb_test.py/adb_device.py.

Enable wireless debugging in the Settings, then 'adb connect
<ip>:<port>'. Connection should succeed if key is in keystore. Used
wireshark to check for packet encryption.

Change-Id: I3d60647491c6c6b92297e4f628707a6457fa9420
diff --git a/adb/daemon/adb_wifi.cpp b/adb/daemon/adb_wifi.cpp
index 2d47719..bce303b 100644
--- a/adb/daemon/adb_wifi.cpp
+++ b/adb/daemon/adb_wifi.cpp
@@ -142,9 +142,9 @@
         close_on_exec(new_fd.get());
         disable_tcp_nagle(new_fd.get());
         std::string serial = android::base::StringPrintf("host-%d", new_fd.get());
-        // TODO: register a tls transport
-        //        register_socket_transport(std::move(new_fd), std::move(serial), port_, 1,
-        //                                  [](atransport*) { return ReconnectResult::Abort; });
+        register_socket_transport(
+                std::move(new_fd), std::move(serial), port_, 1,
+                [](atransport*) { return ReconnectResult::Abort; }, true);
     }
 }
 
@@ -224,4 +224,5 @@
     t->auth_id = adbd_auth_tls_device_connected(auth_ctx, kAdbTransportTypeWifi, t->auth_key.data(),
                                                 t->auth_key.size());
 }
+
 #endif /* !HOST */
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 22ea9ff..2edf582 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -23,10 +23,14 @@
 #include <string.h>
 
 #include <algorithm>
+#include <chrono>
 #include <iomanip>
 #include <map>
 #include <memory>
+#include <thread>
 
+#include <adb/crypto/rsa_2048_key.h>
+#include <adb/tls/adb_ca_list.h>
 #include <adbd_auth.h>
 #include <android-base/file.h>
 #include <android-base/no_destructor.h>
@@ -45,8 +49,14 @@
 #include "transport.h"
 #include "types.h"
 
+using namespace adb::crypto;
+using namespace adb::tls;
+using namespace std::chrono_literals;
+
 static AdbdAuthContext* auth_ctx;
 
+static RSA* rsa_pkey = nullptr;
+
 static void adb_disconnected(void* unused, atransport* t);
 static struct adisconnect adb_disconnect = {adb_disconnected, nullptr};
 
@@ -93,6 +103,55 @@
             &f);
 }
 
+bssl::UniquePtr<STACK_OF(X509_NAME)> adbd_tls_client_ca_list() {
+    if (!auth_required) {
+        return nullptr;
+    }
+
+    bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list(sk_X509_NAME_new_null());
+
+    IteratePublicKeys([&](std::string_view public_key) {
+        // TODO: do we really have to support both ' ' and '\t'?
+        std::vector<std::string> split = android::base::Split(std::string(public_key), " \t");
+        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+        const std::string& pubkey = split[0];
+        if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+            LOG(ERROR) << "Invalid base64 key " << pubkey;
+            return true;
+        }
+
+        RSA* key = nullptr;
+        if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
+            LOG(ERROR) << "Failed to parse key " << pubkey;
+            return true;
+        }
+        bssl::UniquePtr<RSA> rsa_key(key);
+
+        unsigned char* dkey = nullptr;
+        int len = i2d_RSA_PUBKEY(rsa_key.get(), &dkey);
+        if (len <= 0 || dkey == nullptr) {
+            LOG(ERROR) << "Failed to encode RSA public key";
+            return true;
+        }
+
+        uint8_t digest[SHA256_DIGEST_LENGTH];
+        // Put the encoded key in the commonName attribute of the issuer name.
+        // Note that the commonName has a max length of 64 bytes, which is less
+        // than the SHA256_DIGEST_LENGTH.
+        SHA256(dkey, len, digest);
+        OPENSSL_free(dkey);
+
+        auto digest_str = SHA256BitsToHexString(
+                std::string_view(reinterpret_cast<const char*>(&digest[0]), sizeof(digest)));
+        LOG(INFO) << "fingerprint=[" << digest_str << "]";
+        auto issuer = CreateCAIssuerFromEncodedKey(digest_str);
+        CHECK(bssl::PushToStack(ca_list.get(), std::move(issuer)));
+        return true;
+    });
+
+    return ca_list;
+}
+
 bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
                       std::string* auth_key) {
     bool authorized = false;
@@ -217,5 +276,89 @@
 }
 
 void adbd_notify_framework_connected_key(atransport* t) {
-    adbd_auth_notify_auth(auth_ctx, t->auth_key.data(), t->auth_key.size());
+    t->auth_id = adbd_auth_notify_auth(auth_ctx, t->auth_key.data(), t->auth_key.size());
+}
+
+int adbd_tls_verify_cert(X509_STORE_CTX* ctx, std::string* auth_key) {
+    if (!auth_required) {
+        // Any key will do.
+        LOG(INFO) << __func__ << ": auth not required";
+        return 1;
+    }
+
+    bool authorized = false;
+    X509* cert = X509_STORE_CTX_get0_cert(ctx);
+    if (cert == nullptr) {
+        LOG(INFO) << "got null x509 certificate";
+        return 0;
+    }
+    bssl::UniquePtr<EVP_PKEY> evp_pkey(X509_get_pubkey(cert));
+    if (evp_pkey == nullptr) {
+        LOG(INFO) << "got null evp_pkey from x509 certificate";
+        return 0;
+    }
+
+    IteratePublicKeys([&](std::string_view public_key) {
+        // TODO: do we really have to support both ' ' and '\t'?
+        std::vector<std::string> split = android::base::Split(std::string(public_key), " \t");
+        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+        const std::string& pubkey = split[0];
+        if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+            LOG(ERROR) << "Invalid base64 key " << pubkey;
+            return true;
+        }
+
+        RSA* key = nullptr;
+        if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
+            LOG(ERROR) << "Failed to parse key " << pubkey;
+            return true;
+        }
+
+        bool verified = false;
+        bssl::UniquePtr<EVP_PKEY> known_evp(EVP_PKEY_new());
+        EVP_PKEY_set1_RSA(known_evp.get(), key);
+        if (EVP_PKEY_cmp(known_evp.get(), evp_pkey.get())) {
+            LOG(INFO) << "Matched auth_key=" << public_key;
+            verified = true;
+        } else {
+            LOG(INFO) << "auth_key doesn't match [" << public_key << "]";
+        }
+        RSA_free(key);
+        if (verified) {
+            *auth_key = public_key;
+            authorized = true;
+            return false;
+        }
+
+        return true;
+    });
+
+    return authorized ? 1 : 0;
+}
+
+void adbd_auth_tls_handshake(atransport* t) {
+    if (rsa_pkey == nullptr) {
+        // Generate a random RSA key to feed into the X509 certificate
+        auto rsa_2048 = CreateRSA2048Key();
+        CHECK(rsa_2048.has_value());
+        rsa_pkey = EVP_PKEY_get1_RSA(rsa_2048->GetEvpPkey());
+        CHECK(rsa_pkey);
+    }
+
+    std::thread([t]() {
+        std::string auth_key;
+        if (t->connection()->DoTlsHandshake(rsa_pkey, &auth_key)) {
+            LOG(INFO) << "auth_key=" << auth_key;
+            if (t->IsTcpDevice()) {
+                t->auth_key = auth_key;
+                adbd_wifi_secure_connect(t);
+            } else {
+                adbd_auth_verified(t);
+                adbd_notify_framework_connected_key(t);
+            }
+        } else {
+            // Only allow one attempt at the handshake.
+            t->Kick();
+        }
+    }).detach();
 }
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
index 901efee..e458cea 100644
--- a/adb/daemon/transport_qemu.cpp
+++ b/adb/daemon/transport_qemu.cpp
@@ -105,8 +105,9 @@
                  * exchange. */
                 std::string serial = android::base::StringPrintf("host-%d", fd.get());
                 WriteFdExactly(fd.get(), _start_req, strlen(_start_req));
-                register_socket_transport(std::move(fd), std::move(serial), port, 1,
-                                          [](atransport*) { return ReconnectResult::Abort; });
+                register_socket_transport(
+                        std::move(fd), std::move(serial), port, 1,
+                        [](atransport*) { return ReconnectResult::Abort; }, false);
             }
 
             /* Prepare for accepting of the next ADB host connection. */
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a9ad805..c7f8895 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -260,6 +260,12 @@
         CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
     }
 
+    virtual bool DoTlsHandshake(RSA* key, std::string* auth_key) override final {
+        // TODO: support TLS for usb connections.
+        LOG(FATAL) << "Not supported yet.";
+        return false;
+    }
+
   private:
     void StartMonitor() {
         // This is a bit of a mess.