Add adbd tls APIs to adbd_auth library.
Bug: 111434128
Test: mmm -j frameworks/native/libs/adbd_auth
Change-Id: Id285763c2c2dba1666040581d1d2d56e69ff54cb
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 8ac044c..8883c04 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -27,7 +27,7 @@
version_script: "libadbd_auth.map.txt",
stubs: {
- versions: ["1"],
+ versions: ["30"],
symbol_file: "libadbd_auth.map.txt",
},
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index a9c2311..5a0d3f6 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -43,6 +43,8 @@
using android::base::unique_fd;
+static constexpr uint32_t kAuthVersion = 1;
+
struct AdbdAuthPacketAuthenticated {
std::string public_key;
};
@@ -55,8 +57,21 @@
std::string public_key;
};
-using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated, AdbdAuthPacketDisconnected,
- AdbdAuthPacketRequestAuthorization>;
+struct AdbdPacketTlsDeviceConnected {
+ uint8_t transport_type;
+ std::string public_key;
+};
+
+struct AdbdPacketTlsDeviceDisconnected {
+ uint8_t transport_type;
+ std::string public_key;
+};
+
+using AdbdAuthPacket = std::variant<AdbdAuthPacketAuthenticated,
+ AdbdAuthPacketDisconnected,
+ AdbdAuthPacketRequestAuthorization,
+ AdbdPacketTlsDeviceConnected,
+ AdbdPacketTlsDeviceDisconnected>;
struct AdbdAuthContext {
static constexpr uint64_t kEpollConstSocket = 0;
@@ -65,6 +80,7 @@
public:
explicit AdbdAuthContext(AdbdAuthCallbacksV1* callbacks) : next_id_(0), callbacks_(*callbacks) {
+ InitFrameworkHandlers();
epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
if (epoll_fd_ == -1) {
PLOG(FATAL) << "failed to create epoll fd";
@@ -163,34 +179,56 @@
}
}
- void HandlePacket(std::string_view packet) REQUIRES(mutex_) {
+ void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
LOG(INFO) << "received packet: " << packet;
- if (packet.length() < 2) {
- LOG(ERROR) << "received packet of invalid length";
- ReplaceFrameworkFd(unique_fd());
+ if (packet.size() < 2) {
+ LOG(ERROR) << "received packet of invalid length";
+ std::lock_guard<std::mutex> lock(mutex_);
+ ReplaceFrameworkFd(unique_fd());
}
- if (packet[0] == 'O' && packet[1] == 'K') {
- CHECK(this->dispatched_prompt_.has_value());
- auto& [id, key, arg] = *this->dispatched_prompt_;
- keys_.emplace(id, std::move(key));
-
- this->callbacks_.key_authorized(arg, id);
- this->dispatched_prompt_ = std::nullopt;
-
- // We need to dispatch pending prompts here upon success as well,
- // since we might have multiple queued prompts.
- DispatchPendingPrompt();
- } else if (packet[0] == 'N' && packet[1] == 'O') {
- CHECK_EQ(2UL, packet.length());
- // TODO: Do we want a callback if the key is denied?
- this->dispatched_prompt_ = std::nullopt;
- DispatchPendingPrompt();
- } else {
- LOG(ERROR) << "unhandled packet: " << packet;
- ReplaceFrameworkFd(unique_fd());
+ bool handled_packet = false;
+ for (size_t i = 0; i < framework_handlers_.size(); ++i) {
+ if (android::base::ConsumePrefix(&packet, framework_handlers_[i].code)) {
+ framework_handlers_[i].cb(packet);
+ handled_packet = true;
+ break;
+ }
}
+ if (!handled_packet) {
+ LOG(ERROR) << "unhandled packet: " << packet;
+ std::lock_guard<std::mutex> lock(mutex_);
+ ReplaceFrameworkFd(unique_fd());
+ }
+ }
+
+ void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ CHECK(buf.empty());
+ CHECK(dispatched_prompt_.has_value());
+ auto& [id, key, arg] = *dispatched_prompt_;
+ keys_.emplace(id, std::move(key));
+
+ callbacks_.key_authorized(arg, id);
+ dispatched_prompt_ = std::nullopt;
+
+ // We need to dispatch pending prompts here upon success as well,
+ // since we might have multiple queued prompts.
+ DispatchPendingPrompt();
+ }
+
+ void DenyUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ CHECK(buf.empty());
+ // TODO: Do we want a callback if the key is denied?
+ dispatched_prompt_ = std::nullopt;
+ DispatchPendingPrompt();
+ }
+
+ void KeyRemoved(std::string_view buf) EXCLUDES(mutex_) {
+ CHECK(!buf.empty());
+ callbacks_.key_removed(buf.data(), buf.size());
}
bool SendPacket() REQUIRES(mutex_) {
@@ -201,7 +239,8 @@
CHECK_NE(-1, framework_fd_.get());
auto& packet = output_queue_.front();
- struct iovec iovs[2];
+ struct iovec iovs[3];
+ int iovcnt = 2;
if (auto* p = std::get_if<AdbdAuthPacketAuthenticated>(&packet)) {
iovs[0].iov_base = const_cast<char*>("CK");
iovs[0].iov_len = 2;
@@ -217,13 +256,29 @@
iovs[0].iov_len = 2;
iovs[1].iov_base = p->public_key.data();
iovs[1].iov_len = p->public_key.size();
+ } else if (auto* p = std::get_if<AdbdPacketTlsDeviceConnected>(&packet)) {
+ iovcnt = 3;
+ iovs[0].iov_base = const_cast<char*>("WE");
+ iovs[0].iov_len = 2;
+ iovs[1].iov_base = &p->transport_type;
+ iovs[1].iov_len = 1;
+ iovs[2].iov_base = p->public_key.data();
+ iovs[2].iov_len = p->public_key.size();
+ } else if (auto* p = std::get_if<AdbdPacketTlsDeviceDisconnected>(&packet)) {
+ iovcnt = 3;
+ iovs[0].iov_base = const_cast<char*>("WF");
+ iovs[0].iov_len = 2;
+ iovs[1].iov_base = &p->transport_type;
+ iovs[1].iov_len = 1;
+ iovs[2].iov_base = p->public_key.data();
+ iovs[2].iov_len = p->public_key.size();
} else {
LOG(FATAL) << "unhandled packet type?";
}
output_queue_.pop_front();
- ssize_t rc = writev(framework_fd_.get(), iovs, 2);
+ ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
PLOG(ERROR) << "failed to write to framework fd";
ReplaceFrameworkFd(unique_fd());
@@ -308,7 +363,6 @@
std::lock_guard<std::mutex> lock(mutex_);
ReplaceFrameworkFd(unique_fd());
} else {
- std::lock_guard<std::mutex> lock(mutex_);
HandlePacket(std::string_view(buf, rc));
}
}
@@ -329,7 +383,7 @@
}
static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"};
- void IteratePublicKeys(bool (*callback)(const char*, size_t, void*), void* arg) {
+ void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
for (const auto& path : key_paths) {
if (access(path, R_OK) == 0) {
LOG(INFO) << "Loading keys from " << path;
@@ -339,7 +393,7 @@
continue;
}
for (const auto& line : android::base::Split(content, "\n")) {
- if (!callback(line.data(), line.size(), arg)) {
+ if (!callback(opaque, line.data(), line.size())) {
return;
}
}
@@ -361,7 +415,7 @@
std::lock_guard<std::mutex> lock(mutex_);
keys_.emplace(id, public_key);
output_queue_.emplace_back(
- AdbdAuthPacketDisconnected{.public_key = std::string(public_key)});
+ AdbdAuthPacketAuthenticated{.public_key = std::string(public_key)});
return id;
}
@@ -376,6 +430,32 @@
keys_.erase(it);
}
+ uint64_t NotifyTlsDeviceConnected(AdbTransportType type,
+ std::string_view public_key) EXCLUDES(mutex_) {
+ uint64_t id = NextId();
+ std::lock_guard<std::mutex> lock(mutex_);
+ keys_.emplace(id, public_key);
+ output_queue_.emplace_back(AdbdPacketTlsDeviceConnected{
+ .transport_type = static_cast<uint8_t>(type),
+ .public_key = std::string(public_key)});
+ Interrupt();
+ return id;
+ }
+
+ void NotifyTlsDeviceDisconnected(AdbTransportType type, uint64_t id) EXCLUDES(mutex_) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ auto it = keys_.find(id);
+ if (it == keys_.end()) {
+ LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping";
+ return;
+ }
+ output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
+ .transport_type = static_cast<uint8_t>(type),
+ .public_key = std::move(it->second)});
+ keys_.erase(it);
+ Interrupt();
+ }
+
// Interrupt the worker thread to do some work.
void Interrupt() {
uint64_t value = 1;
@@ -387,6 +467,24 @@
}
}
+ void InitFrameworkHandlers() {
+ // Framework wants to disconnect from a secured wifi device
+ framework_handlers_.emplace_back(
+ FrameworkPktHandler{
+ .code = "DD",
+ .cb = std::bind(&AdbdAuthContext::KeyRemoved, this, std::placeholders::_1)});
+ // Framework allows USB debugging for the device
+ framework_handlers_.emplace_back(
+ FrameworkPktHandler{
+ .code = "OK",
+ .cb = std::bind(&AdbdAuthContext::AllowUsbDevice, this, std::placeholders::_1)});
+ // Framework denies USB debugging for the device
+ framework_handlers_.emplace_back(
+ FrameworkPktHandler{
+ .code = "NO",
+ .cb = std::bind(&AdbdAuthContext::DenyUsbDevice, this, std::placeholders::_1)});
+ }
+
unique_fd epoll_fd_;
unique_fd event_fd_;
unique_fd sock_fd_;
@@ -400,19 +498,27 @@
// We keep two separate queues: one to handle backpressure from the socket (output_queue_)
// and one to make sure we only dispatch one authrequest at a time (pending_prompts_).
- std::deque<AdbdAuthPacket> output_queue_;
+ std::deque<AdbdAuthPacket> output_queue_ GUARDED_BY(mutex_);
std::optional<std::tuple<uint64_t, std::string, void*>> dispatched_prompt_ GUARDED_BY(mutex_);
std::deque<std::tuple<uint64_t, std::string, void*>> pending_prompts_ GUARDED_BY(mutex_);
+
+ // This is a list of commands that the framework could send to us.
+ using FrameworkHandlerCb = std::function<void(std::string_view)>;
+ struct FrameworkPktHandler {
+ const char* code;
+ FrameworkHandlerCb cb;
+ };
+ std::vector<FrameworkPktHandler> framework_handlers_;
};
AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) {
- if (callbacks->version != 1) {
+ if (callbacks->version == 1) {
+ return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
+ } else {
LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version;
return nullptr;
}
-
- return new AdbdAuthContext(&callbacks->callbacks.v1);
}
void adbd_auth_delete(AdbdAuthContext* ctx) {
@@ -424,9 +530,9 @@
}
void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
- bool (*callback)(const char* public_key, size_t len, void* arg),
- void* arg) {
- ctx->IteratePublicKeys(callback, arg);
+ bool (*callback)(void* opaque, const char* public_key, size_t len),
+ void* opaque) {
+ ctx->IteratePublicKeys(callback, opaque);
}
uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len) {
@@ -438,10 +544,28 @@
}
void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
- void* arg) {
- ctx->PromptUser(std::string_view(public_key, len), arg);
+ void* opaque) {
+ ctx->PromptUser(std::string_view(public_key, len), opaque);
}
-bool adbd_auth_supports_feature(AdbdAuthFeature) {
+uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
+ AdbTransportType type,
+ const char* public_key,
+ size_t len) {
+ return ctx->NotifyTlsDeviceConnected(type, std::string_view(public_key, len));
+}
+
+void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
+ AdbTransportType type,
+ uint64_t id) {
+ ctx->NotifyTlsDeviceDisconnected(type, id);
+}
+
+uint32_t adbd_auth_get_max_version() {
+ return kAuthVersion;
+}
+
+bool adbd_auth_supports_feature(AdbdAuthFeature f) {
+ UNUSED(f);
return false;
}
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
index b7c1cb8..6ee3166 100644
--- a/libs/adbd_auth/include/adbd_auth.h
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -18,48 +18,159 @@
#include <stdbool.h>
#include <stdint.h>
+#include <sys/cdefs.h>
#include <sys/types.h>
-extern "C" {
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
-struct AdbdAuthCallbacksV1 {
- // Callback for a successful user authorization.
- void (*key_authorized)(void* arg, uint64_t id);
+__BEGIN_DECLS
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
+
+// The transport type of the device connection.
+enum AdbTransportType : int32_t {
+ kAdbTransportTypeUsb = 0,
+ kAdbTransportTypeWifi,
};
+static_assert(sizeof(AdbTransportType) == sizeof(int32_t), "Unexpected AdbTransportType size");
struct AdbdAuthCallbacks {
uint32_t version;
- union {
- AdbdAuthCallbacksV1 v1;
- } callbacks;
+};
+
+struct AdbdAuthCallbacksV1 : AdbdAuthCallbacks {
+ // Callback for a successful user authorization.
+ void (*key_authorized)(void* opaque, uint64_t id);
+ // The framework removed the key from the keystore. This callback notifies
+ // adbd so it can take the appropriate actions (e.g. disconnect all devices
+ // using that key).
+ void (*key_removed)(const char* public_key, size_t length);
};
struct AdbdAuthContext;
+typedef struct AdbdAuthContext AdbdAuthContext;
-AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks);
-void adbd_auth_delete(AdbdAuthContext* ctx);
+/**
+ * Creates a new AdbdAuthContext.
+ *
+ * @param callbacks a set of user-provided callbacks used internally (see
+ * #AdbdAuthCallbacksV1
+ * @return a new AdbdAuthContext instance. Caller is responsible for destroying
+ * the context with #adbd_auth_delete.
+ */
+AdbdAuthContext* adbd_auth_new(AdbdAuthCallbacks* callbacks) __INTRODUCED_IN(30);
-void adbd_auth_run(AdbdAuthContext* ctx);
+/**
+ * Destroys the AdbdAuthContext.
+ *
+ * @param ctx the AdbdAuthContext to destroy.
+ */
+void adbd_auth_delete(AdbdAuthContext* ctx) __INTRODUCED_IN(30);
-// Iterate through the list of authorized public keys.
-// Return false from the callback to stop iteration.
+/**
+ * Starts the AdbdAuthContext.
+ *
+ * The caller may want to run this on a different thread, as this
+ * runs indefinitely.
+ *
+ * @param ctx the AdbdAuthContext
+ */
+void adbd_auth_run(AdbdAuthContext* ctx) __INTRODUCED_IN(30);
+
+/**
+ * Iterate through the list of authorized public keys.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param callback a callback which will get called for every known adb public
+ * key in its keystore. To stop iteration of the keys, return false in the
+ * callback. Otherwise, return true to continue the iteration.
+ * @param opaque an opaque userdata argument
+ */
void adbd_auth_get_public_keys(AdbdAuthContext* ctx,
- bool (*callback)(const char* public_key, size_t len, void* arg),
- void* arg);
+ bool (*callback)(void* opaque, const char* public_key, size_t len),
+ void* opaque) __INTRODUCED_IN(30);
-// Let system_server know that a key has been successfully used for authentication.
-uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx, const char* public_key, size_t len);
+/**
+ * Let system_server know that a key has been successfully used for authentication.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA key that was authorized using the AUTH protocol
+ * @param len the length of the public_key argument
+ * @return an id corresponding to the new connection
+ */
+uint64_t adbd_auth_notify_auth(AdbdAuthContext* ctx,
+ const char* public_key,
+ size_t len) __INTRODUCED_IN(30);
-// Let system_server know that a connection has been closed.
-void adbd_auth_notify_disconnect(AdbdAuthContext* ctx, uint64_t id);
+/**
+ * Let system_server know that an AUTH connection has been closed.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param id the id of the disconnected device
+ */
+void adbd_auth_notify_disconnect(AdbdAuthContext* ctx,
+ uint64_t id) __INTRODUCED_IN(30);
-// Prompt the user to authorize a public key.
-// When this happens, a callback will be run on the auth thread with the result.
-void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* arg);
+/**
+ * Prompt the user to authorize a public key.
+ *
+ * When this happens, a callback will be run on the auth thread with the result.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA public key to prompt user with
+ * @param len the length of the public_key argument
+ * @param arg an opaque userdata argument
+ */
+void adbd_auth_prompt_user(AdbdAuthContext* ctx,
+ const char* public_key,
+ size_t len, void* opaque) __INTRODUCED_IN(30);
-enum AdbdAuthFeature {
+/**
+ * Let system_server know that a TLS device has connected.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param type the transport type of the connection (see #AdbTransportType)
+ * @param public_key the RSA public key used to establish the connection
+ * @param len the length of the public_key argument
+ * @return an id corresponding to the new connection
+ */
+uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
+ AdbTransportType type,
+ const char* public_key,
+ size_t len) __INTRODUCED_IN(30);
+
+/**
+ * Let system_server know that a TLS device has disconnected.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param type the transport type of the connection (see #AdbTransportType)
+ * @param the id of the disconnected device (see #adbd_tls_device_connected)
+ */
+void adbd_auth_tls_device_disconnected(AdbdAuthContext* ctx,
+ AdbTransportType type,
+ uint64_t id) __INTRODUCED_IN(30);
+
+/**
+ * Returns the max #AdbdAuthCallbacks version.
+ *
+ * The version starts at 1, with version 1 corresponding to the
+ * #AdbdAuthCallbacksV1 struct.
+ *
+ * @return the max #AdbdAuthCallbacks version.
+ */
+uint32_t adbd_auth_get_max_version(void) __INTRODUCED_IN(30);
+
+enum AdbdAuthFeature : int32_t {
};
-bool adbd_auth_supports_feature(AdbdAuthFeature f);
+/**
+ * Checks if a feature is supported by the framework. See #AdbdAuthFeature.
+ *
+ * @param feature the feature to check for support
+ * @return true if the feature is supported
+ */
+bool adbd_auth_supports_feature(AdbdAuthFeature feature);
-}
+#endif //!__ANDROID__ || __ANDROID_API__ >= 30
+__END_DECLS
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index d01233c..5857ecb 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -1,13 +1,16 @@
LIBADBD_AUTH {
global:
- adbd_auth_new; # apex
- adbd_auth_delete; # apex
- adbd_auth_run; # apex
- adbd_auth_get_public_keys; #apex
- adbd_auth_notify_auth; # apex
- adbd_auth_notify_disconnect; # apex
- adbd_auth_prompt_user; # apex
- adbd_auth_supports_feature; # apex
+ adbd_auth_new; # apex introduced=30
+ adbd_auth_delete; # apex introduced=30
+ adbd_auth_run; # apex introduced=30
+ adbd_auth_get_public_keys; #apex introduced=30
+ adbd_auth_notify_auth; # apex introduced=30
+ adbd_auth_notify_disconnect; # apex introduced=30
+ adbd_auth_prompt_user; # apex introduced=30
+ adbd_auth_tls_device_connected; # apex introduced=30
+ adbd_auth_tls_device_disconnected; # apex introduced=30
+ adbd_auth_get_max_version; # apex introduced=30
+ adbd_auth_supports_feature; # apex introduced=30
local:
*;
};