platform_system_core/adb/daemon/auth.cpp

222 lines
6.8 KiB
C++
Raw Normal View History

adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define TRACE_TAG AUTH
#include "sysdeps.h"
#include <resolv.h>
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iomanip>
#include <map>
#include <memory>
#include <adbd_auth.h>
#include <android-base/file.h>
#include <android-base/no_destructor.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 <openssl/ssl.h>
#include "adb.h"
#include "adb_auth.h"
#include "adb_io.h"
#include "adb_wifi.h"
#include "fdevent/fdevent.h"
#include "transport.h"
#include "types.h"
static AdbdAuthContext* auth_ctx;
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
static void adb_disconnected(void* unused, atransport* t);
static struct adisconnect adb_disconnect = {adb_disconnected, nullptr};
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
static android::base::NoDestructor<std::map<uint32_t, weak_ptr<atransport>>> transports;
static uint32_t transport_auth_id = 0;
bool auth_required = true;
static void* transport_to_callback_arg(atransport* transport) {
uint32_t id = transport_auth_id++;
(*transports)[id] = transport->weak();
return reinterpret_cast<void*>(id);
}
static atransport* transport_from_callback_arg(void* id) {
uint64_t id_u64 = reinterpret_cast<uint64_t>(id);
if (id_u64 > std::numeric_limits<uint32_t>::max()) {
LOG(FATAL) << "transport_from_callback_arg called on out of range value: " << id_u64;
}
uint32_t id_u32 = static_cast<uint32_t>(id_u64);
auto it = transports->find(id_u32);
if (it == transports->end()) {
LOG(ERROR) << "transport_from_callback_arg failed to find transport for id " << id_u32;
return nullptr;
}
atransport* t = it->second.get();
if (!t) {
LOG(WARNING) << "transport_from_callback_arg found already destructed transport";
return nullptr;
}
transports->erase(it);
return t;
}
static void IteratePublicKeys(std::function<bool(std::string_view public_key)> f) {
adbd_auth_get_public_keys(
auth_ctx,
[](void* opaque, const char* public_key, size_t len) {
return (*static_cast<decltype(f)*>(opaque))(std::string_view(public_key, len));
},
&f);
}
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();
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;
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
}
return true;
});
return authorized;
}
static bool adbd_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;
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
}
void adbd_cloexec_auth_socket() {
int fd = android_get_control_socket("adbd");
if (fd == -1) {
PLOG(ERROR) << "Failed to get adbd socket";
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
return;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
static void adbd_auth_key_authorized(void* arg, uint64_t id) {
LOG(INFO) << "adb client authorized";
fdevent_run_on_main_thread([=]() {
LOG(INFO) << "arg = " << reinterpret_cast<uintptr_t>(arg);
auto* transport = transport_from_callback_arg(arg);
if (!transport) {
LOG(ERROR) << "authorization received for deleted transport, ignoring";
return;
}
transport->auth_id = id;
adbd_auth_verified(transport);
});
}
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
static void adbd_key_removed(const char* public_key, size_t len) {
// The framework removed the key from its keystore. We need to disconnect all
// devices using that key. Search by t->auth_key
std::string_view auth_key(public_key, len);
kick_all_transports_by_auth_key(auth_key);
}
void adbd_auth_init(void) {
AdbdAuthCallbacksV1 cb;
cb.version = 1;
cb.key_authorized = adbd_auth_key_authorized;
cb.key_removed = adbd_key_removed;
auth_ctx = adbd_auth_new(&cb);
adbd_wifi_init(auth_ctx);
std::thread([]() {
adb_thread_setname("adbd auth");
adbd_auth_run(auth_ctx);
LOG(FATAL) << "auth thread terminated";
}).detach();
adb: Add public key authentification Secure adb using a public key authentication, to allow USB debugging only from authorized hosts. When a device is connected to an unauthorized host, the adb daemon sends the user public key to the device. A popup is shown to ask the user to allow debugging once or permanantly from the host. The public key is installed on the device in the later case. Other keys may be installed at build time. On the host, the user public/private key pair is automatically generated, if it does not exist, when the adb daemon starts and is stored in $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed, the ADB_KEYS_PATH env variable may be set to a :-separated (; under Windows) list of private keys, e.g. company-wide or vendor keys. On the device, vendors public keys are installed at build time in /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys. ADB Protocol change: If the device needs to authenticate the host, it replies to CNXN packets with an AUTH packet. The AUTH packet payload is a random token. The host signs the token with one of its private keys and sends an AUTH(0) packet. If the signature verification succeeds, the device replies with a CNXN packet. Otherwise, it sends a new AUTH packet with a new token so that the host can retry with another private key. Once the host has tried all its keys, it can send an AUTH(1) packet with a public key as payload. adbd then sends the public key to the framework (if it has been started) for confirmation. Change-Id: I4e84d7621da956f66ff657245901bdaefead8395
2012-04-12 21:23:49 +02:00
}
void send_auth_request(atransport* t) {
LOG(INFO) << "Calling send_auth_request...";
if (!adbd_auth_generate_token(t->token, sizeof(t->token))) {
PLOG(ERROR) << "Error generating token";
return;
}
apacket* p = get_apacket();
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_TOKEN;
p->msg.data_length = sizeof(t->token);
p->payload.assign(t->token, t->token + sizeof(t->token));
send_packet(p, t);
}
void adbd_auth_verified(atransport* t) {
LOG(INFO) << "adb client authorized";
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(),
transport_to_callback_arg(t));
}
void adbd_notify_framework_connected_key(atransport* t) {
adbd_auth_notify_auth(auth_ctx, t->auth_key.data(), t->auth_key.size());
}