Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d85f5c01 authored by Joshua Duong's avatar Joshua Duong
Browse files

[adbwifi] Add adbwifi_libs, TLS connection, and MDNS implementation.

Bug: 111434128, 119493510, 119494503

Test: Enable wireless debugging in Settings UI, click "pair with pairing code"
to generate pairing code.
On client, 'adb pair <ip_address>', enter pairing code at prompt and hit
enter. Pairing should complete.
'adb logcat'.
Change-Id: I86527bd3fc52e30a8e08ec5843dc3e100abf91fa
Exempt-From-Owner-Approval: approved already
parent 16d5bc6e
Loading
Loading
Loading
Loading
+46 −2
Original line number Diff line number Diff line
@@ -225,9 +225,11 @@ cc_library_host_static {

    srcs: libadb_srcs + [
        "client/auth.cpp",
        "client/adb_wifi.cpp",
        "client/usb_libusb.cpp",
        "client/usb_dispatch.cpp",
        "client/transport_mdns.cpp",
        "client/pairing/pairing_client.cpp",
    ],

    generated_headers: ["platform_tools_version"],
@@ -257,6 +259,8 @@ cc_library_host_static {
    static_libs: [
        "libadb_crypto",
        "libadb_protos",
        "libadb_pairing_connection",
        "libadb_tls_connection",
        "libbase",
        "libcrypto_utils",
        "libcrypto",
@@ -266,6 +270,7 @@ cc_library_host_static {
        "libutils",
        "liblog",
        "libcutils",
        "libprotobuf-cpp-lite",
    ],
}

@@ -274,8 +279,12 @@ cc_test_host {
    defaults: ["adb_defaults"],
    srcs: libadb_test_srcs,
    static_libs: [
        "libadb_crypto",
        "libadb_crypto_static",
        "libadb_host",
        "libadb_pairing_auth_static",
        "libadb_pairing_connection_static",
        "libadb_protos_static",
        "libadb_tls_connection_static",
        "libbase",
        "libcutils",
        "libcrypto_utils",
@@ -283,6 +292,8 @@ cc_test_host {
        "liblog",
        "libmdnssd",
        "libdiagnose_usb",
        "libprotobuf-cpp-lite",
        "libssl",
        "libusb",
    ],

@@ -314,12 +325,16 @@ cc_benchmark {
    },

    static_libs: [
        "libadb_crypto_static",
        "libadb_tls_connection_static",
        "libadbd_auth",
        "libbase",
        "libcutils",
        "libcrypto_utils",
        "libcrypto_static",
        "libdiagnose_usb",
        "liblog",
        "libssl",
        "libusb",
    ],
}
@@ -354,6 +369,10 @@ cc_binary_host {
    static_libs: [
        "libadb_crypto",
        "libadb_host",
	"libadb_pairing_auth",
	"libadb_pairing_connection",
        "libadb_protos",
        "libadb_tls_connection",
        "libandroidfw",
        "libbase",
        "libcutils",
@@ -365,6 +384,7 @@ cc_binary_host {
        "liblz4",
        "libmdnssd",
        "libprotobuf-cpp-lite",
        "libssl",
        "libusb",
        "libutils",
        "liblog",
@@ -415,6 +435,7 @@ cc_library_static {
    srcs: libadb_srcs + libadb_linux_srcs + libadb_posix_srcs + [
        "daemon/auth.cpp",
        "daemon/jdwp_service.cpp",
	"daemon/adb_wifi.cpp",
    ],

    local_include_dirs: [
@@ -430,6 +451,9 @@ cc_library_static {

    shared_libs: [
        "libadb_crypto",
        "libadb_pairing_connection",
        "libadb_protos",
        "libadb_tls_connection",
        "libadbd_auth",
        "libasyncio",
        "libbase",
@@ -484,6 +508,10 @@ cc_library {
    ],

    shared_libs: [
        "libadb_crypto",
        "libadb_pairing_connection",
        "libadb_protos",
        "libadb_tls_connection",
        "libadbd_auth",
        "libasyncio",
        "libbase",
@@ -532,6 +560,9 @@ cc_library {
    ],

    shared_libs: [
        "libadb_crypto",
        "libadb_pairing_connection",
        "libadb_tls_connection",
        "libadbd_auth",
        "libadbd_services",
        "libasyncio",
@@ -580,9 +611,14 @@ cc_binary {
        "libmdnssd",
        "libminijail",
        "libselinux",
        "libssl",
    ],

    shared_libs: [
        "libadb_crypto",
        "libadb_pairing_connection",
        "libadb_protos",
        "libadb_tls_connection",
        "libadbd_auth",
        "libcrypto",
    ],
@@ -659,6 +695,9 @@ cc_test {
    static_libs: [
        "libadbd",
        "libadbd_auth",
        "libadb_crypto_static",
        "libadb_pairing_connection_static",
        "libadb_tls_connection_static",
        "libbase",
        "libcutils",
        "libcrypto_utils",
@@ -773,8 +812,12 @@ cc_test_host {
        "fastdeploy/deploypatchgenerator/patch_utils_test.cpp",
    ],
    static_libs: [
        "libadb_crypto",
        "libadb_crypto_static",
        "libadb_host",
        "libadb_pairing_auth_static",
        "libadb_pairing_connection_static",
        "libadb_protos_static",
        "libadb_tls_connection_static",
        "libandroidfw",
        "libbase",
        "libcutils",
@@ -785,6 +828,7 @@ cc_test_host {
        "liblog",
        "libmdnssd",
        "libprotobuf-cpp-lite",
        "libssl",
        "libusb",
        "libutils",
        "libziparchive",
+1 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ void adb_auth_init();
int adb_auth_keygen(const char* filename);
int adb_auth_pubkey(const char* filename);
std::string adb_auth_get_userkey();
bssl::UniquePtr<EVP_PKEY> adb_auth_get_user_privkey();
std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();

void send_auth_response(const char* token, size_t token_size, atransport* t);

adb/adb_wifi.h

0 → 100644
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#pragma once

#include <string>

#include "adb.h"

#if ADB_HOST

void adb_wifi_init(void);
void adb_wifi_pair_device(const std::string& host, const std::string& password,
                          std::string& response);
bool adb_wifi_is_known_host(const std::string& host);

#else  // !ADB_HOST

struct AdbdAuthContext;

void adbd_wifi_init(AdbdAuthContext* ctx);
void adbd_wifi_secure_connect(atransport* t);

#endif
+6 −3
Original line number Diff line number Diff line
@@ -91,12 +91,15 @@ extern const char* _Nullable * _Nullable __adb_envp;
// ADB Secure DNS service interface. Used to query what ADB Secure DNS services have been
// resolved, and to run some kind of callback for each one.
using adb_secure_foreach_service_callback = std::function<void(
        const char* _Nonnull host_name, const char* _Nonnull ip_address, uint16_t port)>;
        const char* _Nonnull service_name, const char* _Nonnull ip_address, uint16_t port)>;

// Queries pairing/connect services that have been discovered and resolved.
// If |host_name| is not null, run |cb| only for services
// matching |host_name|. Otherwise, run for all services.
void adb_secure_foreach_pairing_service(const char* _Nullable host_name,
void adb_secure_foreach_pairing_service(const char* _Nullable service_name,
                                        adb_secure_foreach_service_callback cb);
void adb_secure_foreach_connect_service(const char* _Nullable host_name,
void adb_secure_foreach_connect_service(const char* _Nullable service_name,
                                        adb_secure_foreach_service_callback cb);
// Tries to connect to a |service_name| if found. Returns true if found and
// connected, false otherwise.
bool adb_secure_connect_by_service_name(const char* _Nonnull service_name);
+246 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#include "adb_wifi.h"

#include <fstream>
#include <random>
#include <thread>

#include <adb/crypto/key.h>
#include <adb/crypto/x509_generator.h>
#include <android-base/file.h>
#include <android-base/parsenetaddress.h>
#include "client/pairing/pairing_client.h"

#include "adb_auth.h"
#include "adb_known_hosts.pb.h"
#include "adb_utils.h"
#include "client/adb_client.h"
#include "sysdeps.h"

using adbwifi::pairing::PairingClient;
using namespace adb::crypto;

struct PairingResultWaiter {
    std::mutex mutex_;
    std::condition_variable cv_;
    std::optional<bool> is_valid_;
    PeerInfo peer_info_;

    static void OnResult(const PeerInfo* peer_info, void* opaque) {
        CHECK(opaque);
        auto* p = reinterpret_cast<PairingResultWaiter*>(opaque);
        {
            std::lock_guard<std::mutex> lock(p->mutex_);
            if (peer_info) {
                memcpy(&(p->peer_info_), peer_info, sizeof(PeerInfo));
            }
            p->is_valid_ = (peer_info != nullptr);
        }
        p->cv_.notify_one();
    }
};  // PairingResultWaiter

void adb_wifi_init() {}

static std::vector<uint8_t> stringToUint8(const std::string& str) {
    auto* p8 = reinterpret_cast<const uint8_t*>(str.data());
    return std::vector<uint8_t>(p8, p8 + str.length());
}

// Tries to replace the |old_file| with |new_file|.
// On success, then |old_file| has been removed and replaced with the
// contents of |new_file|, |new_file| will be removed, and only |old_file| will
// remain.
// On failure, both files will be unchanged.
// |new_file| must exist, but |old_file| does not need to exist.
bool SafeReplaceFile(std::string_view old_file, std::string_view new_file) {
    std::string to_be_deleted(old_file);
    to_be_deleted += ".tbd";

    bool old_renamed = true;
    if (adb_rename(old_file.data(), to_be_deleted.c_str()) != 0) {
        // Don't exit here. This is not necessarily an error, because |old_file|
        // may not exist.
        PLOG(INFO) << "Failed to rename " << old_file;
        old_renamed = false;
    }

    if (adb_rename(new_file.data(), old_file.data()) != 0) {
        PLOG(ERROR) << "Unable to rename file (" << new_file << " => " << old_file << ")";
        if (old_renamed) {
            // Rename the .tbd file back to it's original name
            adb_rename(to_be_deleted.c_str(), old_file.data());
        }
        return false;
    }

    adb_unlink(to_be_deleted.c_str());
    return true;
}

static std::string get_user_known_hosts_path() {
    return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adb_known_hosts.pb";
}

bool load_known_hosts_from_file(const std::string& path, adb::proto::AdbKnownHosts& known_hosts) {
    // Check for file existence.
    struct stat buf;
    if (stat(path.c_str(), &buf) == -1) {
        LOG(INFO) << "Known hosts file [" << path << "] does not exist...";
        return false;
    }

    std::ifstream file(path, std::ios::binary);
    if (!file) {
        PLOG(ERROR) << "Unable to open [" << path << "].";
        return false;
    }

    if (!known_hosts.ParseFromIstream(&file)) {
        PLOG(ERROR) << "Failed to parse [" << path << "]. Deleting it as it may be corrupted.";
        adb_unlink(path.c_str());
        return false;
    }

    return true;
}

static bool write_known_host_to_file(std::string& known_host) {
    std::string path = get_user_known_hosts_path();
    if (path.empty()) {
        PLOG(ERROR) << "Error getting user known hosts filename";
        return false;
    }

    adb::proto::AdbKnownHosts known_hosts;
    load_known_hosts_from_file(path, known_hosts);
    auto* host_info = known_hosts.add_host_infos();
    host_info->set_guid(known_host);

    std::unique_ptr<TemporaryFile> temp_file(new TemporaryFile(adb_get_android_dir_path()));
    if (temp_file->fd == -1) {
        PLOG(ERROR) << "Failed to open [" << temp_file->path << "] for writing";
        return false;
    }

    if (!known_hosts.SerializeToFileDescriptor(temp_file->fd)) {
        LOG(ERROR) << "Unable to write out adb_knowns_hosts";
        return false;
    }
    temp_file->DoNotRemove();
    std::string temp_file_name(temp_file->path);
    temp_file.reset();

    // Replace the existing adb_known_hosts with the new one
    if (!SafeReplaceFile(path, temp_file_name.c_str())) {
        LOG(ERROR) << "Failed to replace old adb_known_hosts";
        adb_unlink(temp_file_name.c_str());
        return false;
    }
    chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP);

    return true;
}

bool adb_wifi_is_known_host(const std::string& host) {
    std::string path = get_user_known_hosts_path();
    if (path.empty()) {
        PLOG(ERROR) << "Error getting user known hosts filename";
        return false;
    }

    adb::proto::AdbKnownHosts known_hosts;
    if (!load_known_hosts_from_file(path, known_hosts)) {
        return false;
    }

    for (const auto& host_info : known_hosts.host_infos()) {
        if (host == host_info.guid()) {
            return true;
        }
    }
    return false;
}

void adb_wifi_pair_device(const std::string& host, const std::string& password,
                          std::string& response) {
    // Check the address for a valid address and port.
    std::string parsed_host;
    std::string err;
    int port = -1;
    if (!android::base::ParseNetAddress(host, &parsed_host, &port, nullptr, &err)) {
        response = "Failed to parse address for pairing: " + err;
        return;
    }
    if (port <= 0 || port > 65535) {
        response = "Invalid port while parsing address [" + host + "]";
        return;
    }

    auto priv_key = adb_auth_get_user_privkey();
    auto x509_cert = GenerateX509Certificate(priv_key.get());
    if (!x509_cert) {
        LOG(ERROR) << "Unable to create X509 certificate for pairing";
        return;
    }
    auto cert_str = X509ToPEMString(x509_cert.get());
    auto priv_str = Key::ToPEMString(priv_key.get());

    // Send our public key on pairing success
    PeerInfo system_info = {};
    system_info.type = ADB_RSA_PUB_KEY;
    std::string public_key = adb_auth_get_userkey();
    CHECK_LE(public_key.size(), sizeof(system_info.data) - 1);  // -1 for null byte
    memcpy(system_info.data, public_key.data(), public_key.size());

    auto pswd8 = stringToUint8(password);
    auto cert8 = stringToUint8(cert_str);
    auto priv8 = stringToUint8(priv_str);

    auto client = PairingClient::Create(pswd8, system_info, cert8, priv8);
    if (client == nullptr) {
        response = "Failed: unable to create pairing client.";
        return;
    }

    PairingResultWaiter waiter;
    std::unique_lock<std::mutex> lock(waiter.mutex_);
    if (!client->Start(host, waiter.OnResult, &waiter)) {
        response = "Failed: Unable to start pairing client.";
        return;
    }
    waiter.cv_.wait(lock, [&]() { return waiter.is_valid_.has_value(); });
    if (!*(waiter.is_valid_)) {
        response = "Failed: Wrong password or connection was dropped.";
        return;
    }

    if (waiter.peer_info_.type != ADB_DEVICE_GUID) {
        response = "Failed: Successfully paired but server returned unknown response=";
        response += waiter.peer_info_.type;
        return;
    }

    std::string device_guid = reinterpret_cast<const char*>(waiter.peer_info_.data);
    response = "Successfully paired to " + host + " [guid=" + device_guid + "]";

    // Write to adb_known_hosts
    write_known_host_to_file(device_guid);
    // Try to auto-connect.
    adb_secure_connect_by_service_name(device_guid.c_str());
}
Loading