Clean up key handling in adb.

This includes the locking we need to be able to re-load the keys at runtime.

We should rename "adb_auth_client.cpp" to "adb_auth_adbd.cpp" or
"adbd_auth.cpp" in a later change.

Change-Id: I9e1d5b6b7d0497d6f6e5d9c4fb660118cdff05a8
Test: "adb devices" works against a non-AOSP device with $ADB_VENDOR_KEYS set, says "unauthorized" without.
Bug: http://b/29273531
diff --git a/adb_auth_client.cpp b/adb_auth_client.cpp
index 415ab8e..9d8dfc0 100644
--- a/adb_auth_client.cpp
+++ b/adb_auth_client.cpp
@@ -16,37 +16,25 @@
 
 #define TRACE_TAG AUTH
 
-#include "sysdeps.h"
+#include "adb.h"
 #include "adb_auth.h"
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
 
 #include <resolv.h>
 #include <stdio.h>
 #include <string.h>
 
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
 #include <openssl/obj_mac.h>
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
-#include <crypto_utils/android_pubkey.h>
-
-#include "cutils/list.h"
-#include "cutils/sockets.h"
-
-#include "adb.h"
-#include "fdevent.h"
-#include "transport.h"
-
-struct adb_public_key {
-    struct listnode node;
-    RSA* key;
-};
-
-static const char *key_paths[] = {
-    "/adb_keys",
-    "/data/misc/adb/adb_keys",
-    NULL
-};
-
 static fdevent listener_fde;
 static fdevent framework_fde;
 static int framework_fd = -1;
@@ -56,135 +44,71 @@
 static atransport* usb_transport;
 static bool needs_retry = false;
 
-static void read_keys(const char *file, struct listnode *list)
-{
-    FILE *f;
-    char buf[MAX_PAYLOAD_V1];
-    char *sep;
-    int ret;
+bool adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int sig_len) {
+    static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
 
-    f = fopen(file, "re");
-    if (!f) {
-        D("Can't open '%s'", file);
-        return;
-    }
+    for (const auto& path : key_paths) {
+        if (access(path, R_OK) == 0) {
+            LOG(INFO) << "Loading keys from " << path;
 
-    while (fgets(buf, sizeof(buf), f)) {
-        auto key = reinterpret_cast<adb_public_key*>(
-            calloc(1, sizeof(adb_public_key)));
-        if (key == nullptr) {
-            D("Can't malloc key");
-            break;
-        }
+            std::string content;
+            if (!android::base::ReadFileToString(path, &content)) {
+                PLOG(ERROR) << "Couldn't read " << path;
+                continue;
+            }
 
-        sep = strpbrk(buf, " \t");
-        if (sep)
-            *sep = '\0';
+            for (const auto& line : android::base::Split(content, "\n")) {
+                // TODO: do we really have to support both ' ' and '\t'?
+                char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t");
+                if (sep) *sep = '\0';
 
-        // b64_pton requires one additional byte in the target buffer for
-        // decoding to succeed. See http://b/28035006 for details.
-        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
-        ret = __b64_pton(buf, keybuf, sizeof(keybuf));
-        if (ret != ANDROID_PUBKEY_ENCODED_SIZE) {
-            D("%s: Invalid base64 data ret=%d", file, ret);
-            free(key);
-            continue;
-        }
+                // b64_pton requires one additional byte in the target buffer for
+                // decoding to succeed. See http://b/28035006 for details.
+                uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+                if (__b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+                    LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
+                    continue;
+                }
 
-        if (!android_pubkey_decode(keybuf, ret, &key->key)) {
-            D("%s: Failed to parse key", file);
-            free(key);
-            continue;
-        }
+                RSA* key = nullptr;
+                if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
+                    LOG(ERROR) << "Failed to parse key " << line.c_str() << " in " << path;
+                    continue;
+                }
 
-        list_add_tail(list, &key->node);
-    }
-
-    fclose(f);
-}
-
-static void free_keys(struct listnode *list)
-{
-    struct listnode *item;
-
-    while (!list_empty(list)) {
-        item = list_head(list);
-        list_remove(item);
-        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
-        RSA_free(key->key);
-        free(key);
-    }
-}
-
-static void load_keys(struct listnode *list)
-{
-    const char* path;
-    const char** paths = key_paths;
-    struct stat buf;
-
-    list_init(list);
-
-    while ((path = *paths++)) {
-        if (!stat(path, &buf)) {
-            D("Loading keys from '%s'", path);
-            read_keys(path, list);
+                bool verified = (RSA_verify(NID_sha1, token, token_size, sig, sig_len, key) == 1);
+                RSA_free(key);
+                if (verified) return true;
+            }
         }
     }
+    return false;
 }
 
-int adb_auth_generate_token(void *token, size_t token_size)
-{
-    FILE *f;
-    int ret;
-
-    f = fopen("/dev/urandom", "re");
-    if (!f)
-        return 0;
-
-    ret = fread(token, token_size, 1, f);
-
-    fclose(f);
-    return ret * token_size;
-}
-
-int adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int siglen)
-{
-    struct listnode *item;
-    struct listnode key_list;
-    int ret = 0;
-
-    load_keys(&key_list);
-
-    list_for_each(item, &key_list) {
-        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
-        ret = RSA_verify(NID_sha1, token, token_size, sig, siglen, key->key);
-        if (ret)
-            break;
-    }
-
-    free_keys(&key_list);
-
-    return ret;
+bool adb_auth_generate_token(void* token, size_t token_size) {
+    FILE* fp = fopen("/dev/urandom", "re");
+    if (!fp) return false;
+    bool okay = (fread(token, token_size, 1, fp) == 1);
+    fclose(fp);
+    return okay;
 }
 
 static void usb_disconnected(void* unused, atransport* t) {
-    D("USB disconnect");
+    LOG(INFO) << "USB disconnect";
     usb_transport = NULL;
     needs_retry = false;
 }
 
 static void framework_disconnected() {
-    D("Framework disconnect");
+    LOG(INFO) << "Framework disconnect";
     fdevent_remove(&framework_fde);
     framework_fd = -1;
 }
 
 static void adb_auth_event(int fd, unsigned events, void*) {
-    char response[2];
-    int ret;
-
     if (events & FDE_READ) {
-        ret = unix_read(fd, response, sizeof(response));
+        char response[2];
+        int ret = unix_read(fd, response, sizeof(response));
         if (ret <= 0) {
             framework_disconnected();
         } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
@@ -195,51 +119,43 @@
     }
 }
 
-void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t)
-{
-    char msg[MAX_PAYLOAD_V1];
-    int ret;
-
+void adb_auth_confirm_key(unsigned char* key, size_t len, atransport* t) {
     if (!usb_transport) {
         usb_transport = t;
         t->AddDisconnect(&usb_disconnect);
     }
 
     if (framework_fd < 0) {
-        D("Client not connected");
+        LOG(ERROR) << "Client not connected";
         needs_retry = true;
         return;
     }
 
     if (key[len - 1] != '\0') {
-        D("Key must be a null-terminated string");
+        LOG(ERROR) << "Key must be a null-terminated string";
         return;
     }
 
-    ret = snprintf(msg, sizeof(msg), "PK%s", key);
-    if (ret >= (signed)sizeof(msg)) {
-        D("Key too long. ret=%d", ret);
+    char msg[MAX_PAYLOAD_V1];
+    int msg_len = snprintf(msg, sizeof(msg), "PK%s", key);
+    if (msg_len >= static_cast<int>(sizeof(msg))) {
+        LOG(ERROR) << "Key too long (" << msg_len << ")";
         return;
     }
-    D("Sending '%s'", msg);
+    LOG(DEBUG) << "Sending '" << msg << "'";
 
-    ret = unix_write(framework_fd, msg, ret);
-    if (ret < 0) {
-        D("Failed to write PK, errno=%d", errno);
+    if (unix_write(framework_fd, msg, msg_len) == -1) {
+        PLOG(ERROR) << "Failed to write PK";
         return;
     }
 }
 
 static void adb_auth_listener(int fd, unsigned events, void* data) {
     sockaddr_storage addr;
-    socklen_t alen;
-    int s;
-
-    alen = sizeof(addr);
-
-    s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
+    socklen_t alen = sizeof(addr);
+    int s = adb_socket_accept(fd, reinterpret_cast<sockaddr*>(&addr), &alen);
     if (s < 0) {
-        D("Failed to accept: errno=%d", errno);
+        PLOG(ERROR) << "Failed to accept";
         return;
     }
 
@@ -261,7 +177,7 @@
 void adbd_cloexec_auth_socket() {
     int fd = android_get_control_socket("adbd");
     if (fd == -1) {
-        D("Failed to get adbd socket");
+        PLOG(ERROR) << "Failed to get adbd socket";
         return;
     }
     fcntl(fd, F_SETFD, FD_CLOEXEC);
@@ -270,12 +186,12 @@
 void adbd_auth_init(void) {
     int fd = android_get_control_socket("adbd");
     if (fd == -1) {
-        D("Failed to get adbd socket");
+        PLOG(ERROR) << "Failed to get adbd socket";
         return;
     }
 
     if (listen(fd, 4) == -1) {
-        D("Failed to listen on '%d'", fd);
+        PLOG(ERROR) << "Failed to listen on '" << fd << "'";
         return;
     }