Merge "adb: add reconnect command."
diff --git a/Android.mk b/Android.mk
index f1d3bee..6693619 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,7 +108,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -131,7 +131,7 @@
 
 # Even though we're building a static library (and thus there's no link step for
 # this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_static libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
 
 LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
 LOCAL_MULTILIB := first
@@ -151,7 +151,7 @@
     shell_service_test.cpp \
 
 LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd
+LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils_static libcrypto_static
 LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
@@ -191,6 +191,7 @@
 LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_STATIC_LIBRARIES := \
     libadb \
+    libcrypto_utils_static \
     libcrypto_static \
     libcutils \
     libdiagnose_usb \
@@ -219,7 +220,7 @@
 LOCAL_SRC_FILES := test_track_devices.cpp
 LOCAL_SANITIZE := $(adb_host_sanitize)
 LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
+LOCAL_STATIC_LIBRARIES := libadb libcrypto_utils_static libcrypto_static libcutils
 LOCAL_LDLIBS += -lrt -ldl -lpthread
 include $(BUILD_HOST_EXECUTABLE)
 endif
@@ -271,6 +272,7 @@
 LOCAL_STATIC_LIBRARIES := \
     libadb \
     libbase \
+    libcrypto_utils_static \
     libcrypto_static \
     libdiagnose_usb \
     liblog \
@@ -342,11 +344,11 @@
     libfec_rs \
     libselinux \
     liblog \
-    libmincrypt \
     libext4_utils_static \
     libsquashfs_utils \
     libcutils \
     libbase \
+    libcrypto_utils_static \
     libcrypto_static \
     libminijail
 
diff --git a/adb.cpp b/adb.cpp
index e0c0503..49d2936 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -353,7 +353,8 @@
                 send_auth_publickey(t);
             }
         } else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
-            if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
+            if (adb_auth_verify(t->token, sizeof(t->token),
+                                p->data, p->msg.data_length)) {
                 adb_auth_verified(t);
                 t->failed_auth_attempts = 0;
             } else {
diff --git a/adb_auth.h b/adb_auth.h
index a13604a..1ab5e1a 100644
--- a/adb_auth.h
+++ b/adb_auth.h
@@ -43,9 +43,15 @@
 void *adb_auth_nextkey(void *current);
 int adb_auth_get_userkey(unsigned char *data, size_t len);
 
-static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
-static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
-static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+static inline int adb_auth_generate_token(void *token, size_t token_size) {
+    return 0;
+}
+static inline int adb_auth_verify(void *token, size_t token_size,
+                                  void *sig, int siglen) {
+    return 0;
+}
+static inline void adb_auth_confirm_key(unsigned char *data, size_t len,
+                                        atransport *t) {}
 
 #else // !ADB_HOST
 
@@ -54,12 +60,15 @@
     return 0;
 }
 static inline void *adb_auth_nextkey(void *current) { return NULL; }
-static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+static inline int adb_auth_get_userkey(unsigned char *data, size_t len) {
+    return 0;
+}
 
 void adbd_auth_init(void);
 void adbd_cloexec_auth_socket();
 int adb_auth_generate_token(void *token, size_t token_size);
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen);
+int adb_auth_verify(uint8_t* token, size_t token_size,
+                    uint8_t* sig, int siglen);
 void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
 
 #endif // ADB_HOST
diff --git a/adb_auth_client.cpp b/adb_auth_client.cpp
index 128c3df..415ab8e 100644
--- a/adb_auth_client.cpp
+++ b/adb_auth_client.cpp
@@ -23,10 +23,14 @@
 #include <stdio.h>
 #include <string.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 "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
 
 #include "adb.h"
 #include "fdevent.h"
@@ -34,7 +38,7 @@
 
 struct adb_public_key {
     struct listnode node;
-    RSAPublicKey key;
+    RSA* key;
 };
 
 static const char *key_paths[] = {
@@ -66,9 +70,8 @@
     }
 
     while (fgets(buf, sizeof(buf), f)) {
-        /* Allocate 4 extra bytes to decode the base64 data in-place */
         auto key = reinterpret_cast<adb_public_key*>(
-            calloc(1, sizeof(adb_public_key) + 4));
+            calloc(1, sizeof(adb_public_key)));
         if (key == nullptr) {
             D("Can't malloc key");
             break;
@@ -78,15 +81,18 @@
         if (sep)
             *sep = '\0';
 
-        ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
-        if (ret != sizeof(key->key)) {
+        // 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;
         }
 
-        if (key->key.len != RSANUMWORDS) {
-            D("%s: Invalid key len %d", file, key->key.len);
+        if (!android_pubkey_decode(keybuf, ret, &key->key)) {
+            D("%s: Failed to parse key", file);
             free(key);
             continue;
         }
@@ -104,7 +110,9 @@
     while (!list_empty(list)) {
         item = list_head(list);
         list_remove(item);
-        free(node_to_item(item, struct adb_public_key, node));
+        adb_public_key* key = node_to_item(item, struct adb_public_key, node);
+        RSA_free(key->key);
+        free(key);
     }
 }
 
@@ -139,20 +147,17 @@
     return ret * token_size;
 }
 
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen)
+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;
 
-    if (siglen != RSANUMBYTES)
-        return 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(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
+        ret = RSA_verify(NID_sha1, token, token_size, sig, siglen, key->key);
         if (ret)
             break;
     }
diff --git a/adb_auth_host.cpp b/adb_auth_host.cpp
index 8f154fd..ab641eb 100644
--- a/adb_auth_host.cpp
+++ b/adb_auth_host.cpp
@@ -37,14 +37,9 @@
 
 #include "adb.h"
 
-/* HACK: we need the RSAPublicKey struct
- * but RSA_verify conflits with openssl */
-#define RSA_verify RSA_verify_mincrypt
-#include "mincrypt/rsa.h"
-#undef RSA_verify
-
 #include <android-base/errors.h>
 #include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
 #include <cutils/list.h>
 
 #include <openssl/evp.h>
@@ -68,54 +63,6 @@
 static struct listnode key_list;
 
 
-/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
-static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
-{
-    int ret = 1;
-    unsigned int i;
-
-    BN_CTX* ctx = BN_CTX_new();
-    BIGNUM* r32 = BN_new();
-    BIGNUM* rr = BN_new();
-    BIGNUM* r = BN_new();
-    BIGNUM* rem = BN_new();
-    BIGNUM* n = BN_new();
-    BIGNUM* n0inv = BN_new();
-
-    if (RSA_size(rsa) != RSANUMBYTES) {
-        ret = 0;
-        goto out;
-    }
-
-    BN_set_bit(r32, 32);
-    BN_copy(n, rsa->n);
-    BN_set_bit(r, RSANUMWORDS * 32);
-    BN_mod_sqr(rr, r, n, ctx);
-    BN_div(NULL, rem, n, r32, ctx);
-    BN_mod_inverse(n0inv, rem, r32, ctx);
-
-    pkey->len = RSANUMWORDS;
-    pkey->n0inv = 0 - BN_get_word(n0inv);
-    for (i = 0; i < RSANUMWORDS; i++) {
-        BN_div(rr, rem, rr, r32, ctx);
-        pkey->rr[i] = BN_get_word(rem);
-        BN_div(n, rem, n, r32, ctx);
-        pkey->n[i] = BN_get_word(rem);
-    }
-    pkey->exponent = BN_get_word(rsa->e);
-
-out:
-    BN_free(n0inv);
-    BN_free(n);
-    BN_free(rem);
-    BN_free(r);
-    BN_free(rr);
-    BN_free(r32);
-    BN_CTX_free(ctx);
-
-    return ret;
-}
-
 static void get_user_info(char *buf, size_t len)
 {
     char hostname[1024], username[1024];
@@ -156,53 +103,55 @@
 
 static int write_public_keyfile(RSA *private_key, const char *private_key_path)
 {
-    RSAPublicKey pkey;
+    uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+    uint8_t* base64_key_data = nullptr;
+    size_t base64_key_length = 0;
     FILE *outfile = NULL;
     char path[PATH_MAX], info[MAX_PAYLOAD_V1];
-    uint8_t* encoded = nullptr;
-    size_t encoded_length;
     int ret = 0;
 
-    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
-        (int)sizeof(path)) {
-        D("Path too long while writing public key");
-        return 0;
-    }
-
-    if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
+    if (!android_pubkey_encode(private_key, binary_key_data,
+                               sizeof(binary_key_data))) {
         D("Failed to convert to publickey");
-        return 0;
-    }
-
-    outfile = fopen(path, "w");
-    if (!outfile) {
-        D("Failed to open '%s'", path);
-        return 0;
+        goto out;
     }
 
     D("Writing public key to '%s'", path);
 
 #if defined(OPENSSL_IS_BORINGSSL)
-    if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
+    if (!EVP_EncodedLength(&base64_key_length, sizeof(binary_key_data))) {
         D("Public key too large to base64 encode");
         goto out;
     }
 #else
     /* While we switch from OpenSSL to BoringSSL we have to implement
      * |EVP_EncodedLength| here. */
-    encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
+    base64_key_length = 1 + ((sizeof(binary_key_data) + 2) / 3 * 4);
 #endif
 
-    encoded = new uint8_t[encoded_length];
-    if (encoded == nullptr) {
+    base64_key_data = new uint8_t[base64_key_length];
+    if (base64_key_data == nullptr) {
         D("Allocation failure");
         goto out;
     }
 
-    encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey));
+    base64_key_length = EVP_EncodeBlock(base64_key_data, binary_key_data,
+                                        sizeof(binary_key_data));
     get_user_info(info, sizeof(info));
 
-    if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
+    if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
+        (int)sizeof(path)) {
+        D("Path too long while writing public key");
+        goto out;
+    }
+
+    outfile = fopen(path, "w");
+    if (!outfile) {
+        D("Failed to open '%s'", path);
+        goto out;
+    }
+
+    if (fwrite(base64_key_data, base64_key_length, 1, outfile) != 1 ||
         fwrite(info, strlen(info), 1, outfile) != 1) {
         D("Write error while writing public key");
         goto out;
@@ -214,7 +163,7 @@
     if (outfile != NULL) {
         fclose(outfile);
     }
-    delete[] encoded;
+    delete[] base64_key_data;
     return ret;
 }
 
diff --git a/commandline.cpp b/commandline.cpp
index 323b9d3..d8b1654 100644
--- a/commandline.cpp
+++ b/commandline.cpp
@@ -1028,50 +1028,40 @@
 #endif /* !defined(_WIN32) */
 }
 
-static bool check_wait_for_device_syntax(const char* service) {
-    // TODO: when we have libc++ for Windows, use a regular expression instead.
-    // wait-for-((any|local|usb)-)?(bootloader|device|recovery|sideload)
-
-    char type[20 + 1]; // sscanf's %20[...] doesn't include the NUL.
-    char state[20 + 1];
-    int length = 0;
-    if (sscanf(service, "wait-for-%20[a-z]-%20[a-z]%n", type, state, &length) < 2 ||
-        length != static_cast<int>(strlen(service))) {
+static bool wait_for_device(const char* service, TransportType t, const char* serial) {
+    std::vector<std::string> components = android::base::Split(service, "-");
+    if (components.size() < 3 || components.size() > 4) {
         fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
         return false;
     }
 
-    if (strcmp(type, "any") != 0 && strcmp(type, "local") != 0 && strcmp(type, "usb") != 0) {
-        fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n", type);
-        return false;
-    }
-    if (strcmp(state, "bootloader") != 0 && strcmp(state, "device") != 0 &&
-        strcmp(state, "recovery") != 0 && strcmp(state, "sideload") != 0) {
-        fprintf(stderr, "adb: unknown state %s; "
-                        "expected 'bootloader', 'device', 'recovery', or 'sideload'\n", state);
-        return false;
-    }
-    return true;
-}
-
-static bool wait_for_device(const char* service, TransportType t, const char* serial) {
     // Was the caller vague about what they'd like us to wait for?
     // If so, check they weren't more specific in their choice of transport type.
-    if (strcmp(service, "wait-for-device") == 0) {
+    if (components.size() == 3) {
+        auto it = components.begin() + 2;
         if (t == kTransportUsb) {
-            service = "wait-for-usb-device";
+            components.insert(it, "usb");
         } else if (t == kTransportLocal) {
-            service = "wait-for-local-device";
+            components.insert(it, "local");
         } else {
-            service = "wait-for-any-device";
+            components.insert(it, "any");
         }
-    }
-
-    if (!check_wait_for_device_syntax(service)) {
+    } else if (components[2] != "any" && components[2] != "local" && components[2] != "usb") {
+        fprintf(stderr, "adb: unknown type %s; expected 'any', 'local', or 'usb'\n",
+                components[2].c_str());
         return false;
     }
 
-    std::string cmd = format_host_command(service, t, serial);
+    if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
+        components[3] != "recovery" && components[3] != "sideload") {
+        fprintf(stderr,
+                "adb: unknown state %s; "
+                "expected 'any', 'bootloader', 'device', 'recovery', or 'sideload'\n",
+                components[3].c_str());
+        return false;
+    }
+
+    std::string cmd = format_host_command(android::base::Join(components, "-").c_str(), t, serial);
     return adb_command(cmd);
 }
 
@@ -1117,7 +1107,7 @@
     TransportType type;
     const char* serial;
     adb_get_transport(&type, &serial);
-    return wait_for_device("wait-for-device", type, serial);
+    return wait_for_device("wait-for-any", type, serial);
 }
 
 // Connects to the device "shell" service with |command| and prints the
diff --git a/services.cpp b/services.cpp
index 3c1aab8..3b212e9 100644
--- a/services.cpp
+++ b/services.cpp
@@ -379,7 +379,7 @@
         std::string error = "unknown error";
         const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
         atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
-        if (t != nullptr && t->connection_state == sinfo->state) {
+        if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->connection_state)) {
             SendOkay(fd);
             break;
         } else if (!is_ambiguous) {
@@ -543,6 +543,8 @@
             sinfo->state = kCsSideload;
         } else if (!strcmp(name, "-bootloader")) {
             sinfo->state = kCsBootloader;
+        } else if (!strcmp(name, "-any")) {
+            sinfo->state = kCsAny;
         } else {
             return nullptr;
         }
diff --git a/shell_service.cpp b/shell_service.cpp
index ce10708..3eeed34 100644
--- a/shell_service.cpp
+++ b/shell_service.cpp
@@ -246,7 +246,7 @@
         char** current = environ;
         while (char* env_cstr = *current++) {
             std::string env_string = env_cstr;
-            char* delimiter = strchr(env_string.c_str(), '=');
+            char* delimiter = strchr(&env_string[0], '=');
 
             // Drop any values that don't contain '='.
             if (delimiter) {
diff --git a/socket.h b/socket.h
index 9eb1b19..4acdf4a 100644
--- a/socket.h
+++ b/socket.h
@@ -118,7 +118,7 @@
 namespace internal {
 
 #if ADB_HOST
-char* skip_host_serial(const char* service);
+char* skip_host_serial(char* service);
 #endif
 
 }  // namespace internal
diff --git a/socket_test.cpp b/socket_test.cpp
index 5cbef6d..20a3bbb 100644
--- a/socket_test.cpp
+++ b/socket_test.cpp
@@ -275,8 +275,8 @@
 
 // Checks that skip_host_serial(serial) returns a pointer to the part of |serial| which matches
 // |expected|, otherwise logs the failure to gtest.
-void VerifySkipHostSerial(const std::string& serial, const char* expected) {
-    const char* result = internal::skip_host_serial(serial.c_str());
+void VerifySkipHostSerial(std::string serial, const char* expected) {
+    char* result = internal::skip_host_serial(&serial[0]);
     if (expected == nullptr) {
         EXPECT_EQ(nullptr, result);
     } else {
diff --git a/sockets.cpp b/sockets.cpp
index c083ee1..aecaba2 100644
--- a/sockets.cpp
+++ b/sockets.cpp
@@ -634,7 +634,7 @@
 // Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
 //
 // The returned pointer will point to the ':' just before <command>, or nullptr if not found.
-char* skip_host_serial(const char* service) {
+char* skip_host_serial(char* service) {
     static const std::vector<std::string>& prefixes =
         *(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});