adbd: use libadbd_auth for authentication.
am: 275232667d
Change-Id: Idadde2911d2661eec4a627c5766f0c8c1040410f
diff --git a/adb/Android.bp b/adb/Android.bp
index d14fe56..9c7a1b9 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -361,6 +361,7 @@
],
shared_libs: [
+ "libadbd_auth",
"libasyncio",
"libbase",
"libcrypto",
@@ -414,6 +415,7 @@
],
shared_libs: [
+ "libadbd_auth",
"libasyncio",
"libbase",
"libcrypto",
@@ -460,6 +462,7 @@
],
shared_libs: [
+ "libadbd_auth",
"libadbd_services",
"libasyncio",
"libbase",
@@ -494,6 +497,7 @@
shared_libs: [
"libadbd",
+ "libadbd_auth",
"libadbd_services",
"libbase",
"libcap",
@@ -509,6 +513,7 @@
name: "adbd_system_binaries",
required: [
"abb",
+ "libadbd_auth",
"reboot",
"set-verity-state",
]
@@ -615,6 +620,7 @@
static_libs: [
"libadbd",
+ "libadbd_auth",
"libbase",
"libcutils",
"libcrypto_utils",
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 1ec145b..9b663be 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -300,6 +300,7 @@
handle_online(t);
#else
if (!auth_required) {
+ LOG(INFO) << "authentication not required";
handle_online(t);
send_connect(t);
} else {
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 7a3a4f5..2e84ce6 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -31,6 +31,7 @@
#include <algorithm>
#include <memory>
+#include <adbd_auth.h>
#include <android-base/file.h>
#include <android-base/strings.h>
#include <crypto_utils/android_pubkey.h>
@@ -38,85 +39,57 @@
#include <openssl/rsa.h>
#include <openssl/sha.h>
-static fdevent* listener_fde = nullptr;
-static fdevent* framework_fde = nullptr;
-static auto& framework_mutex = *new std::mutex();
-static int framework_fd GUARDED_BY(framework_mutex) = -1;
-static auto& connected_keys GUARDED_BY(framework_mutex) = *new std::vector<std::string>;
+static AdbdAuthContext* auth_ctx;
static void adb_disconnected(void* unused, atransport* t);
static struct adisconnect adb_disconnect = {adb_disconnected, nullptr};
-static atransport* adb_transport;
-static bool needs_retry = false;
bool auth_required = true;
-bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
- std::string* auth_key) {
- static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
-
- for (const auto& path : key_paths) {
- if (access(path, R_OK) == 0) {
- LOG(INFO) << "Loading keys from " << path;
- std::string content;
- if (!android::base::ReadFileToString(path, &content)) {
- PLOG(ERROR) << "Couldn't read " << path;
- continue;
- }
-
- for (const auto& line : android::base::Split(content, "\n")) {
- if (line.empty()) continue;
- *auth_key = line;
- // 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];
- if (b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
- LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
- 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;
- }
-
- bool verified =
- (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
- reinterpret_cast<const uint8_t*>(sig.c_str()), sig.size(),
- key) == 1);
- RSA_free(key);
- if (verified) return true;
- }
- }
- }
- auth_key->clear();
- return false;
+static void IteratePublicKeys(std::function<bool(std::string_view public_key)> f) {
+ adbd_auth_get_public_keys(
+ auth_ctx,
+ [](const char* public_key, size_t len, void* arg) {
+ return (*static_cast<decltype(f)*>(arg))(std::string_view(public_key, len));
+ },
+ &f);
}
-static bool adbd_send_key_message_locked(std::string_view msg_type, std::string_view key)
- REQUIRES(framework_mutex) {
- if (framework_fd < 0) {
- LOG(ERROR) << "Client not connected to send msg_type " << msg_type;
- return false;
- }
- std::string msg = std::string(msg_type) + std::string(key);
- int msg_len = msg.length();
- if (msg_len >= static_cast<int>(MAX_FRAMEWORK_PAYLOAD)) {
- LOG(ERROR) << "Key too long (" << msg_len << ")";
- return false;
- }
+bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
+ std::string* auth_key) {
+ bool authorized = false;
+ auth_key->clear();
- LOG(DEBUG) << "Sending '" << msg << "'";
- if (!WriteFdExactly(framework_fd, msg.c_str(), msg_len)) {
- PLOG(ERROR) << "Failed to write " << msg_type;
- return false;
- }
- return true;
+ 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 =
+ (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
+ reinterpret_cast<const uint8_t*>(sig.c_str()), sig.size(), key) == 1);
+ RSA_free(key);
+ if (verified) {
+ *auth_key = public_key;
+ authorized = true;
+ return false;
+ }
+
+ return true;
+ });
+
+ return authorized;
}
static bool adbd_auth_generate_token(void* token, size_t token_size) {
@@ -127,113 +100,6 @@
return okay;
}
-static void adb_disconnected(void* unused, atransport* t) {
- LOG(INFO) << "ADB disconnect";
- adb_transport = nullptr;
- needs_retry = false;
- {
- std::lock_guard<std::mutex> lock(framework_mutex);
- if (framework_fd >= 0) {
- adbd_send_key_message_locked("DC", t->auth_key);
- }
- connected_keys.erase(std::remove(connected_keys.begin(), connected_keys.end(), t->auth_key),
- connected_keys.end());
- }
-}
-
-static void framework_disconnected() {
- LOG(INFO) << "Framework disconnect";
- if (framework_fde) {
- fdevent_destroy(framework_fde);
- {
- std::lock_guard<std::mutex> lock(framework_mutex);
- framework_fd = -1;
- }
- }
-}
-
-static void adbd_auth_event(int fd, unsigned events, void*) {
- if (events & FDE_READ) {
- 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') {
- if (adb_transport) {
- adbd_auth_verified(adb_transport);
- }
- }
- }
-}
-
-void adbd_auth_confirm_key(atransport* t) {
- if (!adb_transport) {
- adb_transport = t;
- t->AddDisconnect(&adb_disconnect);
- }
-
- {
- std::lock_guard<std::mutex> lock(framework_mutex);
- if (framework_fd < 0) {
- LOG(ERROR) << "Client not connected";
- needs_retry = true;
- return;
- }
-
- adbd_send_key_message_locked("PK", t->auth_key);
- }
-}
-
-static void adbd_auth_listener(int fd, unsigned events, void* data) {
- int s = adb_socket_accept(fd, nullptr, nullptr);
- if (s < 0) {
- PLOG(ERROR) << "Failed to accept";
- return;
- }
-
- {
- std::lock_guard<std::mutex> lock(framework_mutex);
- if (framework_fd >= 0) {
- LOG(WARNING) << "adb received framework auth socket connection again";
- framework_disconnected();
- }
-
- framework_fd = s;
- framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr);
- fdevent_add(framework_fde, FDE_READ);
-
- if (needs_retry) {
- needs_retry = false;
- send_auth_request(adb_transport);
- }
-
- // if a client connected before the framework was available notify the framework of the
- // connected key now.
- if (!connected_keys.empty()) {
- for (const auto& key : connected_keys) {
- adbd_send_key_message_locked("CK", key);
- }
- }
- }
-}
-
-void adbd_notify_framework_connected_key(atransport* t) {
- if (!adb_transport) {
- adb_transport = t;
- t->AddDisconnect(&adb_disconnect);
- }
- {
- std::lock_guard<std::mutex> lock(framework_mutex);
- if (std::find(connected_keys.begin(), connected_keys.end(), t->auth_key) ==
- connected_keys.end()) {
- connected_keys.push_back(t->auth_key);
- }
- if (framework_fd >= 0) {
- adbd_send_key_message_locked("CK", t->auth_key);
- }
- }
-}
-
void adbd_cloexec_auth_socket() {
int fd = android_get_control_socket("adbd");
if (fd == -1) {
@@ -243,20 +109,23 @@
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
+static void adbd_auth_key_authorized(void* arg, uint64_t id) {
+ LOG(INFO) << "adb client authorized";
+ auto* transport = static_cast<atransport*>(arg);
+ transport->auth_id = id;
+ adbd_auth_verified(transport);
+}
+
void adbd_auth_init(void) {
- int fd = android_get_control_socket("adbd");
- if (fd == -1) {
- PLOG(ERROR) << "Failed to get adbd socket";
- return;
- }
-
- if (listen(fd, 4) == -1) {
- PLOG(ERROR) << "Failed to listen on '" << fd << "'";
- return;
- }
-
- listener_fde = fdevent_create(fd, adbd_auth_listener, nullptr);
- fdevent_add(listener_fde, FDE_READ);
+ AdbdAuthCallbacks cb;
+ cb.version = 1;
+ cb.callbacks.v1.key_authorized = adbd_auth_key_authorized;
+ auth_ctx = adbd_auth_new(&cb);
+ std::thread([]() {
+ adb_thread_setname("adbd auth");
+ adbd_auth_run(auth_ctx);
+ LOG(FATAL) << "auth thread terminated";
+ }).detach();
}
void send_auth_request(atransport* t) {
@@ -280,3 +149,18 @@
handle_online(t);
send_connect(t);
}
+
+static void adb_disconnected(void* unused, atransport* t) {
+ LOG(INFO) << "ADB disconnect";
+ adbd_auth_notify_disconnect(auth_ctx, t->auth_id);
+}
+
+void adbd_auth_confirm_key(atransport* t) {
+ LOG(INFO) << "prompting user to authorize key";
+ t->AddDisconnect(&adb_disconnect);
+ adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(), t);
+}
+
+void adbd_notify_framework_connected_key(atransport* t) {
+ adbd_auth_notify_auth(auth_ctx, t->auth_key.data(), t->auth_key.size());
+}
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index cbb5e69..7277cc8 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -218,8 +218,6 @@
}
#endif
- adbd_auth_init();
-
// Our external storage path may be different than apps, since
// we aren't able to bind mount after dropping root.
const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
@@ -234,6 +232,9 @@
drop_privileges(server_port);
#endif
+ // adbd_auth_init will spawn a thread, so we need to defer it until after selinux transitions.
+ adbd_auth_init();
+
bool is_usb = false;
#if defined(__ANDROID__)
diff --git a/adb/transport.h b/adb/transport.h
index c38cb1d..89d76b8 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -277,8 +277,11 @@
std::string device;
std::string devpath;
+#if !ADB_HOST
// Used to provide the key to the framework.
std::string auth_key;
+ uint64_t auth_id;
+#endif
bool IsTcpDevice() const { return type == kTransportLocal; }