Merge "Add project ID constants."
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d6945e3..0ec505d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -4,6 +4,12 @@
"name": "adbd_test"
},
{
+ "name": "adb_crypto_test"
+ },
+ {
+ "name": "adb_tls_connection_test"
+ },
+ {
"name": "CtsInitTestCases"
},
{
diff --git a/adb/Android.bp b/adb/Android.bp
index 675525c..c71138a 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -255,6 +255,8 @@
},
static_libs: [
+ "libadb_crypto",
+ "libadb_protos",
"libbase",
"libcrypto_utils",
"libcrypto",
@@ -272,6 +274,7 @@
defaults: ["adb_defaults"],
srcs: libadb_test_srcs,
static_libs: [
+ "libadb_crypto",
"libadb_host",
"libbase",
"libcutils",
@@ -347,6 +350,7 @@
],
static_libs: [
+ "libadb_crypto",
"libadb_host",
"libandroidfw",
"libbase",
@@ -422,6 +426,7 @@
],
shared_libs: [
+ "libadb_crypto",
"libadbd_auth",
"libasyncio",
"libbase",
@@ -765,6 +770,7 @@
"fastdeploy/deploypatchgenerator/patch_utils_test.cpp",
],
static_libs: [
+ "libadb_crypto",
"libadb_host",
"libandroidfw",
"libbase",
diff --git a/adb/adb_mdns.h b/adb/adb_mdns.h
index 2e544d7..6b37355 100644
--- a/adb/adb_mdns.h
+++ b/adb/adb_mdns.h
@@ -17,6 +17,72 @@
#ifndef _ADB_MDNS_H_
#define _ADB_MDNS_H_
+#include <android-base/macros.h>
+
const char* kADBServiceType = "_adb._tcp";
+const char* kADBSecurePairingServiceType = "_adb_secure_pairing._tcp";
+const char* kADBSecureConnectServiceType = "_adb_secure_connect._tcp";
+
+const int kADBTransportServiceRefIndex = 0;
+const int kADBSecurePairingServiceRefIndex = 1;
+const int kADBSecureConnectServiceRefIndex = 2;
+
+// Each ADB Secure service advertises with a TXT record indicating the version
+// using a key/value pair per RFC 6763 (https://tools.ietf.org/html/rfc6763).
+//
+// The first key/value pair is always the version of the protocol.
+// There may be more key/value pairs added after.
+//
+// The version is purposely represented as the single letter "v" due to the
+// need to minimize DNS traffic. The version starts at 1. With each breaking
+// protocol change, the version is incremented by 1.
+//
+// Newer adb clients/daemons need to recognize and either reject
+// or be backward-compatible with older verseions if there is a mismatch.
+//
+// Relevant sections:
+//
+// """
+// 6.4. Rules for Keys in DNS-SD Key/Value Pairs
+//
+// The key MUST be at least one character. DNS-SD TXT record strings
+// beginning with an '=' character (i.e., the key is missing) MUST be
+// silently ignored.
+//
+// ...
+//
+// 6.5. Rules for Values in DNS-SD Key/Value Pairs
+//
+// If there is an '=' in a DNS-SD TXT record string, then everything
+// after the first '=' to the end of the string is the value. The value
+// can contain any eight-bit values including '='.
+// """
+
+#define ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ver) ("v=" #ver)
+
+// Client/service versions are initially defined to be matching,
+// but may go out of sync as different clients and services
+// try to talk to each other.
+#define ADB_SECURE_SERVICE_VERSION 1
+#define ADB_SECURE_CLIENT_VERSION ADB_SECURE_SERVICE_VERSION
+
+const char* kADBSecurePairingServiceTxtRecord =
+ ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION);
+const char* kADBSecureConnectServiceTxtRecord =
+ ADB_SECURE_SERVICE_VERSION_TXT_RECORD(ADB_SECURE_SERVICE_VERSION);
+
+const char* kADBDNSServices[] = {
+ kADBServiceType,
+ kADBSecurePairingServiceType,
+ kADBSecureConnectServiceType,
+};
+
+const char* kADBDNSServiceTxtRecords[] = {
+ nullptr,
+ kADBSecurePairingServiceTxtRecord,
+ kADBSecureConnectServiceTxtRecord,
+};
+
+const int kNumADBDNSServices = arraysize(kADBDNSServices);
#endif
diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h
index ba53041..758fcab 100644
--- a/adb/client/adb_client.h
+++ b/adb/client/adb_client.h
@@ -16,6 +16,7 @@
#pragma once
+#include <functional>
#include <optional>
#include <string>
@@ -86,3 +87,16 @@
// Globally acccesible argv/envp, for the purpose of re-execing adb.
extern const char* _Nullable * _Nullable __adb_argv;
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)>;
+
+// 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,
+ adb_secure_foreach_service_callback cb);
+void adb_secure_foreach_connect_service(const char* _Nullable host_name,
+ adb_secure_foreach_service_callback cb);
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index e8be784..dcf4bc0 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -29,6 +29,7 @@
#include <set>
#include <string>
+#include <adb/crypto/rsa_2048_key.h>
#include <android-base/errors.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
@@ -53,100 +54,50 @@
*new std::map<std::string, std::shared_ptr<RSA>>;
static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
-static std::string get_user_info() {
- std::string hostname;
- if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
- char buf[64];
- if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
- if (hostname.empty()) hostname = "unknown";
+using namespace adb::crypto;
- std::string username;
- if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined(_WIN32)
- if (username.empty() && getlogin()) username = getlogin();
-#endif
- if (username.empty()) hostname = "unknown";
-
- return " " + username + "@" + hostname;
-}
-
-static bool calculate_public_key(std::string* out, RSA* private_key) {
- uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
- if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
- LOG(ERROR) << "Failed to convert to public key";
- return false;
- }
-
- size_t expected_length;
- if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) {
- LOG(ERROR) << "Public key too large to base64 encode";
- return false;
- }
-
- out->resize(expected_length);
- size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
- sizeof(binary_key_data));
- out->resize(actual_length);
- out->append(get_user_info());
- return true;
-}
-
-static int generate_key(const std::string& file) {
+static bool generate_key(const std::string& file) {
LOG(INFO) << "generate_key(" << file << ")...";
- mode_t old_mask;
- FILE *f = nullptr;
- int ret = 0;
+ auto rsa_2048 = CreateRSA2048Key();
+ if (!rsa_2048) {
+ LOG(ERROR) << "Unable to create key";
+ return false;
+ }
std::string pubkey;
- EVP_PKEY* pkey = EVP_PKEY_new();
- BIGNUM* exponent = BN_new();
- RSA* rsa = RSA_new();
- if (!pkey || !exponent || !rsa) {
- LOG(ERROR) << "Failed to allocate key";
- goto out;
- }
+ RSA* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+ CHECK(rsa);
- BN_set_word(exponent, RSA_F4);
- RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
- EVP_PKEY_set1_RSA(pkey, rsa);
-
- if (!calculate_public_key(&pubkey, rsa)) {
+ if (!CalculatePublicKey(&pubkey, rsa)) {
LOG(ERROR) << "failed to calculate public key";
- goto out;
+ return false;
}
- old_mask = umask(077);
+ mode_t old_mask = umask(077);
- f = fopen(file.c_str(), "w");
+ std::unique_ptr<FILE, decltype(&fclose)> f(nullptr, &fclose);
+ f.reset(fopen(file.c_str(), "w"));
if (!f) {
PLOG(ERROR) << "Failed to open " << file;
umask(old_mask);
- goto out;
+ return false;
}
umask(old_mask);
- if (!PEM_write_PrivateKey(f, pkey, nullptr, nullptr, 0, nullptr, nullptr)) {
+ if (!PEM_write_PrivateKey(f.get(), rsa_2048->GetEvpPkey(), nullptr, nullptr, 0, nullptr,
+ nullptr)) {
LOG(ERROR) << "Failed to write key";
- goto out;
+ return false;
}
if (!android::base::WriteStringToFile(pubkey, file + ".pub")) {
PLOG(ERROR) << "failed to write public key";
- goto out;
+ return false;
}
- ret = 1;
-
-out:
- if (f) fclose(f);
- EVP_PKEY_free(pkey);
- RSA_free(rsa);
- BN_free(exponent);
- return ret;
+ return true;
}
static std::string hash_key(RSA* key) {
@@ -325,7 +276,7 @@
if (!privkey) {
return false;
}
- return calculate_public_key(out, privkey.get());
+ return CalculatePublicKey(out, privkey.get());
}
std::string adb_auth_get_userkey() {
@@ -343,7 +294,7 @@
}
int adb_auth_keygen(const char* filename) {
- return (generate_key(filename) == 0);
+ return !generate_key(filename);
}
int adb_auth_pubkey(const char* filename) {
diff --git a/adb/client/transport_mdns.cpp b/adb/client/transport_mdns.cpp
index 1a34384..f5811a4 100644
--- a/adb/client/transport_mdns.cpp
+++ b/adb/client/transport_mdns.cpp
@@ -25,17 +25,33 @@
#endif
#include <thread>
+#include <vector>
#include <android-base/stringprintf.h>
#include <dns_sd.h>
+#include "adb_client.h"
#include "adb_mdns.h"
#include "adb_trace.h"
#include "fdevent/fdevent.h"
#include "sysdeps.h"
-static DNSServiceRef service_ref;
-static fdevent* service_ref_fde;
+static DNSServiceRef service_refs[kNumADBDNSServices];
+static fdevent* service_ref_fdes[kNumADBDNSServices];
+
+static int adb_DNSServiceIndexByName(const char* regType) {
+ for (int i = 0; i < kNumADBDNSServices; ++i) {
+ if (!strncmp(regType, kADBDNSServices[i], strlen(kADBDNSServices[i]))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static bool adb_DNSServiceShouldConnect(const char* regType) {
+ int index = adb_DNSServiceIndexByName(regType);
+ return index == kADBTransportServiceRefIndex;
+}
// Use adb_DNSServiceRefSockFD() instead of calling DNSServiceRefSockFD()
// directly so that the socket is put through the appropriate compatibility
@@ -94,10 +110,16 @@
public:
virtual ~ResolvedService() = default;
- ResolvedService(std::string name, uint32_t interfaceIndex,
- const char* hosttarget, uint16_t port) :
- name_(name),
- port_(port) {
+ ResolvedService(std::string serviceName, std::string regType, uint32_t interfaceIndex,
+ const char* hosttarget, uint16_t port, int version)
+ : serviceName_(serviceName),
+ regType_(regType),
+ hosttarget_(hosttarget),
+ port_(port),
+ sa_family_(0),
+ ip_addr_data_(NULL),
+ serviceVersion_(version) {
+ memset(ip_addr_, 0, sizeof(ip_addr_));
/* TODO: We should be able to get IPv6 support by adding
* kDNSServiceProtocol_IPv6 to the flags below. However, when we do
@@ -116,45 +138,135 @@
} else {
Initialize();
}
+
+ D("Client version: %d Service version: %d\n", clientVersion_, serviceVersion_);
}
void Connect(const sockaddr* address) {
- char ip_addr[INET6_ADDRSTRLEN];
- const void* ip_addr_data;
+ sa_family_ = address->sa_family;
const char* addr_format;
- if (address->sa_family == AF_INET) {
- ip_addr_data =
- &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
+ if (sa_family_ == AF_INET) {
+ ip_addr_data_ = &reinterpret_cast<const sockaddr_in*>(address)->sin_addr;
addr_format = "%s:%hu";
- } else if (address->sa_family == AF_INET6) {
- ip_addr_data =
- &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
+ } else if (sa_family_ == AF_INET6) {
+ ip_addr_data_ = &reinterpret_cast<const sockaddr_in6*>(address)->sin6_addr;
addr_format = "[%s]:%hu";
- } else { // Should be impossible
+ } else { // Should be impossible
D("mDNS resolved non-IP address.");
return;
}
// Winsock version requires the const cast Because Microsoft.
- if (!inet_ntop(address->sa_family, const_cast<void*>(ip_addr_data),
- ip_addr, INET6_ADDRSTRLEN)) {
+ if (!inet_ntop(sa_family_, const_cast<void*>(ip_addr_data_), ip_addr_, sizeof(ip_addr_))) {
D("Could not convert IP address to string.");
return;
}
- std::string response;
- connect_device(android::base::StringPrintf(addr_format, ip_addr, port_),
- &response);
- D("Connect to %s (%s:%hu) : %s", name_.c_str(), ip_addr, port_,
- response.c_str());
+ // adb secure service needs to do something different from just
+ // connecting here.
+ if (adb_DNSServiceShouldConnect(regType_.c_str())) {
+ std::string response;
+ connect_device(android::base::StringPrintf(addr_format, ip_addr_, port_), &response);
+ D("Connect to %s regtype %s (%s:%hu) : %s", serviceName_.c_str(), regType_.c_str(),
+ ip_addr_, port_, response.c_str());
+ } else {
+ D("Not immediately connecting to serviceName=[%s], regtype=[%s] ipaddr=(%s:%hu)",
+ serviceName_.c_str(), regType_.c_str(), ip_addr_, port_);
+ }
+
+ int adbSecureServiceType = serviceIndex();
+ switch (adbSecureServiceType) {
+ case kADBSecurePairingServiceRefIndex:
+ sAdbSecurePairingServices->push_back(this);
+ break;
+ case kADBSecureConnectServiceRefIndex:
+ sAdbSecureConnectServices->push_back(this);
+ break;
+ default:
+ break;
+ }
}
+ int serviceIndex() const { return adb_DNSServiceIndexByName(regType_.c_str()); }
+
+ std::string hostTarget() const { return hosttarget_; }
+
+ std::string ipAddress() const { return ip_addr_; }
+
+ uint16_t port() const { return port_; }
+
+ using ServiceRegistry = std::vector<ResolvedService*>;
+
+ static ServiceRegistry* sAdbSecurePairingServices;
+ static ServiceRegistry* sAdbSecureConnectServices;
+
+ static void initAdbSecure();
+
+ static void forEachService(const ServiceRegistry& services, const std::string& hostname,
+ adb_secure_foreach_service_callback cb);
+
private:
- std::string name_;
+ int clientVersion_ = ADB_SECURE_CLIENT_VERSION;
+ std::string serviceName_;
+ std::string regType_;
+ std::string hosttarget_;
const uint16_t port_;
+ int sa_family_;
+ const void* ip_addr_data_;
+ char ip_addr_[INET6_ADDRSTRLEN];
+ int serviceVersion_;
};
+// static
+std::vector<ResolvedService*>* ResolvedService::sAdbSecurePairingServices = NULL;
+
+// static
+std::vector<ResolvedService*>* ResolvedService::sAdbSecureConnectServices = NULL;
+
+// static
+void ResolvedService::initAdbSecure() {
+ if (!sAdbSecurePairingServices) {
+ sAdbSecurePairingServices = new ServiceRegistry;
+ }
+ if (!sAdbSecureConnectServices) {
+ sAdbSecureConnectServices = new ServiceRegistry;
+ }
+}
+
+// static
+void ResolvedService::forEachService(const ServiceRegistry& services,
+ const std::string& wanted_host,
+ adb_secure_foreach_service_callback cb) {
+ initAdbSecure();
+
+ for (auto service : services) {
+ auto hostname = service->hostTarget();
+ auto ip = service->ipAddress();
+ auto port = service->port();
+
+ if (wanted_host == "") {
+ cb(hostname.c_str(), ip.c_str(), port);
+ } else if (hostname == wanted_host) {
+ cb(hostname.c_str(), ip.c_str(), port);
+ }
+ }
+}
+
+// static
+void adb_secure_foreach_pairing_service(const char* host_name,
+ adb_secure_foreach_service_callback cb) {
+ ResolvedService::forEachService(*ResolvedService::sAdbSecurePairingServices,
+ host_name ? host_name : "", cb);
+}
+
+// static
+void adb_secure_foreach_connect_service(const char* host_name,
+ adb_secure_foreach_service_callback cb) {
+ ResolvedService::forEachService(*ResolvedService::sAdbSecureConnectServices,
+ host_name ? host_name : "", cb);
+}
+
static void DNSSD_API register_service_ip(DNSServiceRef /*sdRef*/,
DNSServiceFlags /*flags*/,
uint32_t /*interfaceIndex*/,
@@ -167,6 +279,12 @@
std::unique_ptr<ResolvedService> data(
reinterpret_cast<ResolvedService*>(context));
data->Connect(address);
+
+ // For ADB Secure services, keep those ResolvedService's around
+ // for later processing with secure connection establishment.
+ if (data->serviceIndex() != kADBTransportServiceRefIndex) {
+ data.release();
+ }
}
static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
@@ -182,18 +300,23 @@
class DiscoveredService : public AsyncServiceRef {
public:
- DiscoveredService(uint32_t interfaceIndex, const char* serviceName,
- const char* regtype, const char* domain)
- : serviceName_(serviceName) {
-
+ DiscoveredService(uint32_t interfaceIndex, const char* serviceName, const char* regtype,
+ const char* domain)
+ : serviceName_(serviceName), regType_(regtype) {
DNSServiceErrorType ret =
DNSServiceResolve(&sdRef_, 0, interfaceIndex, serviceName, regtype,
domain, register_resolved_mdns_service,
reinterpret_cast<void*>(this));
- if (ret != kDNSServiceErr_NoError) {
- D("Got %d from DNSServiceResolve.", ret);
- } else {
+ D("DNSServiceResolve for "
+ "interfaceIndex %u "
+ "serviceName %s "
+ "regtype %s "
+ "domain %s "
+ ": %d",
+ interfaceIndex, serviceName, regtype, domain, ret);
+
+ if (ret == kDNSServiceErr_NoError) {
Initialize();
}
}
@@ -202,20 +325,62 @@
return serviceName_.c_str();
}
+ const char* RegType() { return regType_.c_str(); }
+
private:
std::string serviceName_;
+ std::string regType_;
};
-static void DNSSD_API register_resolved_mdns_service(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* fullname,
- const char* hosttarget,
- uint16_t port,
- uint16_t /*txtLen*/,
- const unsigned char* /*txtRecord*/,
- void* context) {
+// Returns the version the device wanted to advertise,
+// or -1 if parsing fails.
+static int parse_version_from_txt_record(uint16_t txtLen, const unsigned char* txtRecord) {
+ if (!txtLen) return -1;
+ if (!txtRecord) return -1;
+
+ // https://tools.ietf.org/html/rfc6763
+ // """
+ // 6.1. General Format Rules for DNS TXT Records
+ //
+ // A DNS TXT record can be up to 65535 (0xFFFF) bytes long. The total
+ // length is indicated by the length given in the resource record header
+ // in the DNS message. There is no way to tell directly from the data
+ // alone how long it is (e.g., there is no length count at the start, or
+ // terminating NULL byte at the end).
+ // """
+
+ // Let's trust the TXT record's length byte
+ // Worst case, it wastes 255 bytes
+ std::vector<char> recordAsString(txtLen + 1, '\0');
+ char* str = recordAsString.data();
+
+ memcpy(str, txtRecord + 1 /* skip the length byte */, txtLen);
+
+ // Check if it's the version key
+ static const char* versionKey = "v=";
+ size_t versionKeyLen = strlen(versionKey);
+
+ if (strncmp(versionKey, str, versionKeyLen)) return -1;
+
+ auto valueStart = str + versionKeyLen;
+
+ long parsedNumber = strtol(valueStart, 0, 10);
+
+ // No valid conversion. Also, 0
+ // is not a valid version.
+ if (!parsedNumber) return -1;
+
+ // Outside bounds of long.
+ if (parsedNumber == LONG_MIN || parsedNumber == LONG_MAX) return -1;
+
+ // Possibly valid version
+ return static_cast<int>(parsedNumber);
+}
+
+static void DNSSD_API register_resolved_mdns_service(
+ DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+ DNSServiceErrorType errorCode, const char* fullname, const char* hosttarget, uint16_t port,
+ uint16_t txtLen, const unsigned char* txtRecord, void* context) {
D("Resolved a service.");
std::unique_ptr<DiscoveredService> discovered(
reinterpret_cast<DiscoveredService*>(context));
@@ -225,10 +390,14 @@
return;
}
+ // TODO: Reject certain combinations of invalid or mismatched client and
+ // service versions here before creating anything.
+ // At the moment, there is nothing to reject, so accept everything
+ // as an optimistic default.
+ auto serviceVersion = parse_version_from_txt_record(txtLen, txtRecord);
- auto resolved =
- new ResolvedService(discovered->ServiceName(),
- interfaceIndex, hosttarget, ntohs(port));
+ auto resolved = new ResolvedService(discovered->ServiceName(), discovered->RegType(),
+ interfaceIndex, hosttarget, ntohs(port), serviceVersion);
if (! resolved->Initialized()) {
delete resolved;
@@ -239,19 +408,18 @@
}
}
-static void DNSSD_API register_mdns_transport(DNSServiceRef sdRef,
- DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* serviceName,
- const char* regtype,
- const char* domain,
- void* /*context*/) {
+static void DNSSD_API on_service_browsed(DNSServiceRef sdRef, DNSServiceFlags flags,
+ uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+ const char* serviceName, const char* regtype,
+ const char* domain, void* /*context*/) {
D("Registering a transport.");
if (errorCode != kDNSServiceErr_NoError) {
D("Got error %d during mDNS browse.", errorCode);
DNSServiceRefDeallocate(sdRef);
- fdevent_destroy(service_ref_fde);
+ int serviceIndex = adb_DNSServiceIndexByName(regtype);
+ if (serviceIndex != -1) {
+ fdevent_destroy(service_ref_fdes[serviceIndex]);
+ }
return;
}
@@ -262,21 +430,27 @@
}
void init_mdns_transport_discovery_thread(void) {
- DNSServiceErrorType errorCode = DNSServiceBrowse(&service_ref, 0, 0, kADBServiceType, nullptr,
- register_mdns_transport, nullptr);
+ int errorCodes[kNumADBDNSServices];
- if (errorCode != kDNSServiceErr_NoError) {
- D("Got %d initiating mDNS browse.", errorCode);
- return;
+ for (int i = 0; i < kNumADBDNSServices; ++i) {
+ errorCodes[i] = DNSServiceBrowse(&service_refs[i], 0, 0, kADBDNSServices[i], nullptr,
+ on_service_browsed, nullptr);
+
+ if (errorCodes[i] != kDNSServiceErr_NoError) {
+ D("Got %d browsing for mDNS service %s.", errorCodes[i], kADBDNSServices[i]);
+ }
+
+ if (errorCodes[i] == kDNSServiceErr_NoError) {
+ fdevent_run_on_main_thread([i]() {
+ service_ref_fdes[i] = fdevent_create(adb_DNSServiceRefSockFD(service_refs[i]),
+ pump_service_ref, &service_refs[i]);
+ fdevent_set(service_ref_fdes[i], FDE_READ);
+ });
+ }
}
-
- fdevent_run_on_main_thread([]() {
- service_ref_fde =
- fdevent_create(adb_DNSServiceRefSockFD(service_ref), pump_service_ref, &service_ref);
- fdevent_set(service_ref_fde, FDE_READ);
- });
}
void init_mdns_transport_discovery(void) {
+ ResolvedService::initAdbSecure();
std::thread(init_mdns_transport_discovery_thread).detach();
}
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
new file mode 100644
index 0000000..da4869a
--- /dev/null
+++ b/adb/crypto/Android.bp
@@ -0,0 +1,85 @@
+// 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.
+
+cc_defaults {
+ name: "libadb_crypto_defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wthread-safety",
+ "-Werror",
+ ],
+
+ compile_multilib: "both",
+
+ srcs: [
+ "key.cpp",
+ "rsa_2048_key.cpp",
+ "x509_generator.cpp",
+ ],
+
+ target: {
+ windows: {
+ compile_multilib: "first",
+ enabled: true,
+ },
+ },
+
+ export_include_dirs: ["include"],
+
+ visibility: [
+ "//system/core/adb:__subpackages__",
+ ],
+
+ host_supported: true,
+ recovery_available: true,
+
+ stl: "libc++_static",
+
+ shared_libs: [
+ "libadb_protos",
+ "libbase",
+ "liblog",
+ "libcrypto",
+ "libcrypto_utils",
+ ],
+}
+
+cc_library {
+ name: "libadb_crypto",
+ defaults: ["libadb_crypto_defaults"],
+
+ apex_available: [
+ "com.android.adbd",
+ "test_com.android.adbd",
+ ],
+
+ static_libs: [
+ "libadb_protos",
+ ],
+}
+
+// For running atest (b/147158681)
+cc_library_static {
+ name: "libadb_crypto_static",
+ defaults: ["libadb_crypto_defaults"],
+
+ apex_available: [
+ "//apex_available:platform",
+ ],
+
+ static_libs: [
+ "libadb_protos_static",
+ ],
+}
diff --git a/adb/crypto/include/adb/crypto/key.h b/adb/crypto/include/adb/crypto/key.h
new file mode 100644
index 0000000..d9ce69e
--- /dev/null
+++ b/adb/crypto/include/adb/crypto/key.h
@@ -0,0 +1,46 @@
+/*
+ * 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 <openssl/evp.h>
+
+#include "key_type.pb.h"
+
+namespace adb {
+namespace crypto {
+
+// Class that represents a public/private key pair.
+class Key {
+ public:
+ explicit Key(bssl::UniquePtr<EVP_PKEY>&& pkey, adb::proto::KeyType type)
+ : pkey_(std::move(pkey)), key_type_(type) {}
+ Key(Key&&) = default;
+ Key& operator=(Key&&) = default;
+
+ EVP_PKEY* GetEvpPkey() const { return pkey_.get(); }
+ adb::proto::KeyType GetKeyType() const { return key_type_; }
+ static std::string ToPEMString(EVP_PKEY* pkey);
+
+ private:
+ bssl::UniquePtr<EVP_PKEY> pkey_;
+ adb::proto::KeyType key_type_;
+}; // Key
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/include/adb/crypto/rsa_2048_key.h b/adb/crypto/include/adb/crypto/rsa_2048_key.h
new file mode 100644
index 0000000..2983a84
--- /dev/null
+++ b/adb/crypto/include/adb/crypto/rsa_2048_key.h
@@ -0,0 +1,34 @@
+/*
+ * 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 <memory>
+#include <optional>
+
+#include "adb/crypto/key.h"
+
+namespace adb {
+namespace crypto {
+
+// Create a new RSA2048 key pair.
+std::optional<Key> CreateRSA2048Key();
+
+// Generates the public key from the RSA private key.
+bool CalculatePublicKey(std::string* out, RSA* private_key);
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/include/adb/crypto/x509_generator.h b/adb/crypto/include/adb/crypto/x509_generator.h
new file mode 100644
index 0000000..a269243
--- /dev/null
+++ b/adb/crypto/include/adb/crypto/x509_generator.h
@@ -0,0 +1,31 @@
+/*
+ * 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 <openssl/x509v3.h>
+
+namespace adb {
+namespace crypto {
+
+// Generate a X.509 certificate based on the key |pkey|.
+bssl::UniquePtr<X509> GenerateX509Certificate(EVP_PKEY* pkey);
+
+// Convert X509* to PEM string format
+std::string X509ToPEMString(X509* x509);
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/key.cpp b/adb/crypto/key.cpp
new file mode 100644
index 0000000..4d87006
--- /dev/null
+++ b/adb/crypto/key.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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/crypto/key.h"
+
+#include <android-base/logging.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+namespace adb {
+namespace crypto {
+
+// static
+std::string Key::ToPEMString(EVP_PKEY* pkey) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ int rc = PEM_write_bio_PKCS8PrivateKey(bio.get(), pkey, nullptr, nullptr, 0, nullptr, nullptr);
+ if (rc != 1) {
+ LOG(ERROR) << "PEM_write_bio_PKCS8PrivateKey failed";
+ return "";
+ }
+
+ BUF_MEM* mem = nullptr;
+ BIO_get_mem_ptr(bio.get(), &mem);
+ if (!mem || !mem->data || !mem->length) {
+ LOG(ERROR) << "BIO_get_mem_ptr failed";
+ return "";
+ }
+
+ return std::string(mem->data, mem->length);
+}
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/rsa_2048_key.cpp b/adb/crypto/rsa_2048_key.cpp
new file mode 100644
index 0000000..7911af9
--- /dev/null
+++ b/adb/crypto/rsa_2048_key.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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/crypto/rsa_2048_key.h"
+
+#include <android-base/logging.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+namespace adb {
+namespace crypto {
+
+namespace {
+std::string get_user_info() {
+ std::string hostname;
+ if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
+#if !defined(_WIN32)
+ char buf[64];
+ if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
+#endif
+ if (hostname.empty()) hostname = "unknown";
+
+ std::string username;
+ if (getenv("LOGNAME")) username = getenv("LOGNAME");
+#if !defined(_WIN32)
+ if (username.empty() && getlogin()) username = getlogin();
+#endif
+ if (username.empty()) hostname = "unknown";
+
+ return " " + username + "@" + hostname;
+}
+
+} // namespace
+
+bool CalculatePublicKey(std::string* out, RSA* private_key) {
+ uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+ if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
+ LOG(ERROR) << "Failed to convert to public key";
+ return false;
+ }
+
+ size_t expected_length;
+ if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) {
+ LOG(ERROR) << "Public key too large to base64 encode";
+ return false;
+ }
+
+ out->resize(expected_length);
+ size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
+ sizeof(binary_key_data));
+ out->resize(actual_length);
+ out->append(get_user_info());
+ return true;
+}
+
+std::optional<Key> CreateRSA2048Key() {
+ bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+ bssl::UniquePtr<BIGNUM> exponent(BN_new());
+ bssl::UniquePtr<RSA> rsa(RSA_new());
+ if (!pkey || !exponent || !rsa) {
+ LOG(ERROR) << "Failed to allocate key";
+ return std::nullopt;
+ }
+
+ BN_set_word(exponent.get(), RSA_F4);
+ RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr);
+ EVP_PKEY_set1_RSA(pkey.get(), rsa.get());
+
+ return std::optional<Key>{Key(std::move(pkey), adb::proto::KeyType::RSA_2048)};
+}
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/tests/Android.bp b/adb/crypto/tests/Android.bp
new file mode 100644
index 0000000..b32dcf7
--- /dev/null
+++ b/adb/crypto/tests/Android.bp
@@ -0,0 +1,41 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "adb_crypto_test",
+ srcs: [
+ "rsa_2048_key_test.cpp",
+ "x509_generator_test.cpp",
+ ],
+
+ compile_multilib: "first",
+
+ shared_libs: [
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libprotobuf-cpp-lite",
+ ],
+
+ // Let's statically link them so we don't have to install it onto the
+ // system image for testing.
+ static_libs: [
+ "libadb_crypto_static",
+ "libadb_protos_static",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/adb/crypto/tests/key_test.cpp b/adb/crypto/tests/key_test.cpp
new file mode 100644
index 0000000..1feb6e8
--- /dev/null
+++ b/adb/crypto/tests/key_test.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <resolv.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+namespace adb {
+namespace crypto {
+
+TEST(RSA2048Key, Smoke) {
+ auto rsa_2048 = CreateRSA2048Key();
+ EXPECT_NE(rsa_2048, std::nullopt);
+ EXPECT_EQ(rsa_2048->GetKeyType(), adb::proto::KeyType::RSA_2048);
+ ASSERT_NE(rsa_2048->GetEvpPkey(), nullptr);
+
+ // The public key string format is expected to be: "<pub_key> <host_name>"
+ std::string pub_key_plus_name;
+ auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+ ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa));
+ std::vector<std::string> split = android::base::Split(std::string(pub_key_plus_name), " \t");
+ EXPECT_EQ(split.size(), 2);
+
+ LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]";
+
+ // Try to sign something and decode it.
+ const char token[SHA_DIGEST_LENGTH] = "abcdefghij123456789";
+ std::vector<uint8_t> sig(RSA_size(rsa));
+ unsigned sig_len;
+ EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token), sig.data(),
+ &sig_len, rsa),
+ 1);
+ sig.resize(sig_len);
+
+ {
+ uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+ const std::string& pubkey = split[0];
+ ASSERT_EQ(b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)), ANDROID_PUBKEY_ENCODED_SIZE);
+ RSA* key = nullptr;
+ ASSERT_TRUE(android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key));
+ EXPECT_EQ(RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token),
+ sig.data(), sig.size(), key),
+ 1);
+ RSA_free(key);
+ }
+}
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/tests/rsa_2048_key_test.cpp b/adb/crypto/tests/rsa_2048_key_test.cpp
new file mode 100644
index 0000000..1d8880e
--- /dev/null
+++ b/adb/crypto/tests/rsa_2048_key_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <resolv.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+namespace adb {
+namespace crypto {
+
+TEST(RSA2048Key, Smoke) {
+ auto rsa_2048 = CreateRSA2048Key();
+ EXPECT_NE(rsa_2048, std::nullopt);
+ EXPECT_EQ(rsa_2048->GetKeyType(), adb::proto::KeyType::RSA_2048);
+ ASSERT_NE(rsa_2048->GetEvpPkey(), nullptr);
+
+ // The public key string format is expected to be: "<pub_key> <host_name>"
+ std::string pub_key_plus_name;
+ auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+ ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa));
+ std::vector<std::string> split = android::base::Split(std::string(pub_key_plus_name), " \t");
+ EXPECT_EQ(split.size(), 2);
+
+ LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]";
+
+ std::string pemString = Key::ToPEMString(rsa_2048->GetEvpPkey());
+ ASSERT_FALSE(pemString.empty());
+
+ // Try to sign something and decode it.
+ const char token[SHA_DIGEST_LENGTH] = "abcdefghij123456789";
+ std::vector<uint8_t> sig(RSA_size(rsa));
+ unsigned sig_len;
+ EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token), sig.data(),
+ &sig_len, rsa),
+ 1);
+ sig.resize(sig_len);
+
+ {
+ uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+ const std::string& pubkey = split[0];
+ ASSERT_EQ(b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)), ANDROID_PUBKEY_ENCODED_SIZE);
+ RSA* key = nullptr;
+ ASSERT_TRUE(android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key));
+ EXPECT_EQ(RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token),
+ sig.data(), sig.size(), key),
+ 1);
+ RSA_free(key);
+ }
+}
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/tests/x509_generator_test.cpp b/adb/crypto/tests/x509_generator_test.cpp
new file mode 100644
index 0000000..281776b
--- /dev/null
+++ b/adb/crypto/tests/x509_generator_test.cpp
@@ -0,0 +1,45 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <adb/crypto/x509_generator.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+namespace adb {
+namespace crypto {
+
+TEST(X509Generator, Smoke) {
+ auto rsa_2048 = CreateRSA2048Key();
+
+ std::string pub_key_plus_name;
+ auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+ ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa));
+ std::vector<std::string> split = android::base::Split(std::string(pub_key_plus_name), " \t");
+ EXPECT_EQ(split.size(), 2);
+
+ LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]";
+ auto x509_cert = GenerateX509Certificate(rsa_2048->GetEvpPkey());
+ ASSERT_NE(x509_cert.get(), nullptr);
+
+ std::string x509_str = X509ToPEMString(x509_cert.get());
+ ASSERT_FALSE(x509_str.empty());
+}
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/crypto/x509_generator.cpp b/adb/crypto/x509_generator.cpp
new file mode 100644
index 0000000..43b8153
--- /dev/null
+++ b/adb/crypto/x509_generator.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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/crypto/x509_generator.h"
+
+#include <vector>
+
+#include <android-base/logging.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+namespace adb {
+namespace crypto {
+
+namespace {
+
+const char kBasicConstraints[] = "critical,CA:TRUE";
+const char kKeyUsage[] = "critical,keyCertSign,cRLSign,digitalSignature";
+const char kSubjectKeyIdentifier[] = "hash";
+constexpr int kCertLifetimeSeconds = 10 * 365 * 24 * 60 * 60;
+
+bool add_ext(X509* cert, int nid, const char* value) {
+ size_t len = strlen(value) + 1;
+ std::vector<char> mutableValue(value, value + len);
+ X509V3_CTX context;
+
+ X509V3_set_ctx_nodb(&context);
+
+ X509V3_set_ctx(&context, cert, cert, nullptr, nullptr, 0);
+ X509_EXTENSION* ex = X509V3_EXT_nconf_nid(nullptr, &context, nid, mutableValue.data());
+ if (!ex) {
+ return false;
+ }
+
+ X509_add_ext(cert, ex, -1);
+ X509_EXTENSION_free(ex);
+ return true;
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> GenerateX509Certificate(EVP_PKEY* pkey) {
+ CHECK(pkey);
+ bssl::UniquePtr<X509> x509(X509_new());
+ if (!x509) {
+ LOG(ERROR) << "Unable to allocate x509 container";
+ return nullptr;
+ }
+ X509_set_version(x509.get(), 2);
+
+ ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), 1);
+ X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
+ X509_gmtime_adj(X509_get_notAfter(x509.get()), kCertLifetimeSeconds);
+
+ if (!X509_set_pubkey(x509.get(), pkey)) {
+ LOG(ERROR) << "Unable to set x509 public key";
+ return nullptr;
+ }
+
+ X509_NAME* name = X509_get_subject_name(x509.get());
+ if (!name) {
+ LOG(ERROR) << "Unable to get x509 subject name";
+ return nullptr;
+ }
+ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>("US"), -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>("Android"), -1, -1, 0);
+ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>("Adb"), -1, -1, 0);
+ if (!X509_set_issuer_name(x509.get(), name)) {
+ LOG(ERROR) << "Unable to set x509 issuer name";
+ return nullptr;
+ }
+
+ add_ext(x509.get(), NID_basic_constraints, kBasicConstraints);
+ add_ext(x509.get(), NID_key_usage, kKeyUsage);
+ add_ext(x509.get(), NID_subject_key_identifier, kSubjectKeyIdentifier);
+
+ int bytes = X509_sign(x509.get(), pkey, EVP_sha256());
+ if (bytes <= 0) {
+ LOG(ERROR) << "Unable to sign x509 certificate";
+ return nullptr;
+ }
+
+ return x509;
+}
+
+std::string X509ToPEMString(X509* x509) {
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+ int rc = PEM_write_bio_X509(bio.get(), x509);
+ if (rc != 1) {
+ LOG(ERROR) << "PEM_write_bio_X509 failed";
+ return "";
+ }
+
+ BUF_MEM* mem = nullptr;
+ BIO_get_mem_ptr(bio.get(), &mem);
+ if (!mem || !mem->data || !mem->length) {
+ LOG(ERROR) << "BIO_get_mem_ptr failed";
+ return "";
+ }
+
+ return std::string(mem->data, mem->length);
+}
+
+} // namespace crypto
+} // namespace adb
diff --git a/adb/daemon/mdns.cpp b/adb/daemon/mdns.cpp
index 3530f48..fa98340 100644
--- a/adb/daemon/mdns.cpp
+++ b/adb/daemon/mdns.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "mdns.h"
#include "adb_mdns.h"
#include "sysdeps.h"
@@ -32,8 +33,8 @@
static std::mutex& mdns_lock = *new std::mutex();
static int port;
-static DNSServiceRef mdns_ref;
-static bool mdns_registered = false;
+static DNSServiceRef mdns_refs[kNumADBDNSServices];
+static bool mdns_registered[kNumADBDNSServices];
static void start_mdns() {
if (android::base::GetProperty("init.svc.mdnsd", "") == "running") {
@@ -60,34 +61,86 @@
}
}
-static void setup_mdns_thread() {
- start_mdns();
+static void register_mdns_service(int index, int port) {
std::lock_guard<std::mutex> lock(mdns_lock);
std::string hostname = "adb-";
hostname += android::base::GetProperty("ro.serialno", "unidentified");
- auto error = DNSServiceRegister(&mdns_ref, 0, 0, hostname.c_str(),
- kADBServiceType, nullptr, nullptr,
- htobe16((uint16_t)port), 0, nullptr,
- mdns_callback, nullptr);
+ // https://tools.ietf.org/html/rfc6763
+ // """
+ // The format of the data within a DNS TXT record is one or more
+ // strings, packed together in memory without any intervening gaps or
+ // padding bytes for word alignment.
+ //
+ // The format of each constituent string within the DNS TXT record is a
+ // single length byte, followed by 0-255 bytes of text data.
+ // """
+ //
+ // Therefore:
+ // 1. Begin with the string length
+ // 2. No null termination
+
+ std::vector<char> txtRecord;
+
+ if (kADBDNSServiceTxtRecords[index]) {
+ size_t txtRecordStringLength = strlen(kADBDNSServiceTxtRecords[index]);
+
+ txtRecord.resize(1 + // length byte
+ txtRecordStringLength // string bytes
+ );
+
+ txtRecord[0] = (char)txtRecordStringLength;
+ memcpy(txtRecord.data() + 1, kADBDNSServiceTxtRecords[index], txtRecordStringLength);
+ }
+
+ auto error = DNSServiceRegister(
+ &mdns_refs[index], 0, 0, hostname.c_str(), kADBDNSServices[index], nullptr, nullptr,
+ htobe16((uint16_t)port), (uint16_t)txtRecord.size(),
+ txtRecord.empty() ? nullptr : txtRecord.data(), mdns_callback, nullptr);
if (error != kDNSServiceErr_NoError) {
- LOG(ERROR) << "Could not register mDNS service (" << error << ").";
- return;
+ LOG(ERROR) << "Could not register mDNS service " << kADBDNSServices[index] << ", error ("
+ << error << ").";
+ mdns_registered[index] = false;
}
- mdns_registered = true;
+ mdns_registered[index] = true;
+
+ LOG(INFO) << "adbd mDNS service " << kADBDNSServices[index]
+ << " registered: " << mdns_registered[index];
}
-static void teardown_mdns() {
+static void unregister_mdns_service(int index) {
std::lock_guard<std::mutex> lock(mdns_lock);
- if (mdns_registered) {
- DNSServiceRefDeallocate(mdns_ref);
+ if (mdns_registered[index]) {
+ DNSServiceRefDeallocate(mdns_refs[index]);
}
}
+static void register_base_mdns_transport() {
+ register_mdns_service(kADBTransportServiceRefIndex, port);
+}
+
+static void setup_mdns_thread() {
+ start_mdns();
+
+ // We will now only set up the normal transport mDNS service
+ // instead of registering all the adb secure mDNS services
+ // in the beginning. This is to provide more privacy/security.
+ register_base_mdns_transport();
+}
+
+// This also tears down any adb secure mDNS services, if they exist.
+static void teardown_mdns() {
+ for (int i = 0; i < kNumADBDNSServices; ++i) {
+ unregister_mdns_service(i);
+ }
+}
+
+// Public interface/////////////////////////////////////////////////////////////
+
void setup_mdns(int port_in) {
port = port_in;
std::thread(setup_mdns_thread).detach();
@@ -95,3 +148,33 @@
// TODO: Make this more robust against a hard kill.
atexit(teardown_mdns);
}
+
+void register_adb_secure_pairing_service(int port) {
+ std::thread([port]() {
+ register_mdns_service(kADBSecurePairingServiceRefIndex, port);
+ }).detach();
+}
+
+void unregister_adb_secure_pairing_service() {
+ std::thread([]() { unregister_mdns_service(kADBSecurePairingServiceRefIndex); }).detach();
+}
+
+bool is_adb_secure_pairing_service_registered() {
+ std::lock_guard<std::mutex> lock(mdns_lock);
+ return mdns_registered[kADBSecurePairingServiceRefIndex];
+}
+
+void register_adb_secure_connect_service(int port) {
+ std::thread([port]() {
+ register_mdns_service(kADBSecureConnectServiceRefIndex, port);
+ }).detach();
+}
+
+void unregister_adb_secure_connect_service() {
+ std::thread([]() { unregister_mdns_service(kADBSecureConnectServiceRefIndex); }).detach();
+}
+
+bool is_adb_secure_connect_service_registered() {
+ std::lock_guard<std::mutex> lock(mdns_lock);
+ return mdns_registered[kADBSecureConnectServiceRefIndex];
+}
diff --git a/adb/daemon/mdns.h b/adb/daemon/mdns.h
index 4c6b1ca..a18093b 100644
--- a/adb/daemon/mdns.h
+++ b/adb/daemon/mdns.h
@@ -19,4 +19,12 @@
void setup_mdns(int port);
+void register_adb_secure_pairing_service(int port);
+void unregister_adb_secure_pairing_service(int port);
+bool is_adb_secure_pairing_service_registered();
+
+void register_adb_secure_connect_service(int port);
+void unregister_adb_secure_connect_service(int port);
+bool is_adb_secure_connect_service_registered();
+
#endif // _DAEMON_MDNS_H_
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
new file mode 100644
index 0000000..a7e5d9c
--- /dev/null
+++ b/adb/proto/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 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.
+
+cc_defaults {
+ name: "libadb_protos_defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wthread-safety",
+ "-Werror",
+ ],
+
+ compile_multilib: "both",
+
+ proto: {
+ export_proto_headers: true,
+ type: "lite",
+ },
+ srcs: [
+ "adb_known_hosts.proto",
+ "key_type.proto",
+ "pairing.proto",
+ ],
+ target: {
+ windows: {
+ compile_multilib: "first",
+ enabled: true,
+ },
+ },
+
+ visibility: [
+ "//system/core/adb:__subpackages__",
+ ],
+
+ stl: "libc++_static",
+
+ host_supported: true,
+ recovery_available: true,
+}
+
+cc_library {
+ name: "libadb_protos",
+ defaults: ["libadb_protos_defaults"],
+
+ apex_available: [
+ "com.android.adbd",
+ "test_com.android.adbd",
+ ],
+}
+
+// For running atest (b/147158681)
+cc_library_static {
+ name: "libadb_protos_static",
+ defaults: ["libadb_protos_defaults"],
+
+ apex_available: [
+ "//apex_available:platform",
+ ],
+}
diff --git a/adb/proto/adb_known_hosts.proto b/adb/proto/adb_known_hosts.proto
new file mode 100644
index 0000000..85d1489
--- /dev/null
+++ b/adb/proto/adb_known_hosts.proto
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "AdbKnownHostsProto";
+
+package adb.proto;
+
+// Each known host
+message HostInfo {
+ string guid = 1;
+}
+
+// Protobuf definition for the adb_known_hosts.
+message AdbKnownHosts {
+ repeated HostInfo host_infos = 1;
+}
diff --git a/adb/proto/jarjar-rules.txt b/adb/proto/jarjar-rules.txt
new file mode 100644
index 0000000..4e40637
--- /dev/null
+++ b/adb/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.** com.android.framework.protobuf.@1
diff --git a/adb/proto/key_type.proto b/adb/proto/key_type.proto
new file mode 100644
index 0000000..ed451c5
--- /dev/null
+++ b/adb/proto/key_type.proto
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "KeyTypeProto";
+
+package adb.proto;
+
+enum KeyType {
+ RSA_2048 = 0;
+}
diff --git a/adb/proto/pairing.proto b/adb/proto/pairing.proto
new file mode 100644
index 0000000..b0be20e
--- /dev/null
+++ b/adb/proto/pairing.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "PairingProto";
+
+package adb.proto;
+
+// The type of packets used in the pairing protocol
+message PairingPacket {
+ enum Type {
+ SPAKE2_MSG = 0;
+ PEER_INFO = 1;
+ }
+}
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
new file mode 100644
index 0000000..49833ff
--- /dev/null
+++ b/adb/tls/Android.bp
@@ -0,0 +1,75 @@
+// Copyright (C) 2020 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.
+
+cc_defaults {
+ name: "libadb_tls_connection_defaults",
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Wthread-safety",
+ "-Werror",
+ ],
+
+ compile_multilib: "both",
+
+ srcs: [
+ "adb_ca_list.cpp",
+ "tls_connection.cpp",
+ ],
+ target: {
+ windows: {
+ compile_multilib: "first",
+ enabled: true,
+ },
+ },
+ export_include_dirs: ["include"],
+
+ host_supported: true,
+ recovery_available: true,
+
+ visibility: [
+ "//system/core/adb:__subpackages__",
+ ],
+
+ stl: "libc++_static",
+
+ static_libs: [
+ "libbase",
+ ],
+ shared_libs: [
+ "libcrypto",
+ "liblog",
+ "libssl",
+ ],
+}
+
+cc_library {
+ name: "libadb_tls_connection",
+ defaults: ["libadb_tls_connection_defaults"],
+
+ apex_available: [
+ "com.android.adbd",
+ "test_com.android.adbd",
+ ],
+}
+
+// For running atest (b/147158681)
+cc_library_static {
+ name: "libadb_tls_connection_static",
+ defaults: ["libadb_tls_connection_defaults"],
+
+ apex_available: [
+ "//apex_available:platform",
+ ],
+}
diff --git a/adb/tls/adb_ca_list.cpp b/adb/tls/adb_ca_list.cpp
new file mode 100644
index 0000000..36afe42
--- /dev/null
+++ b/adb/tls/adb_ca_list.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 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/tls/adb_ca_list.h"
+
+#include <iomanip>
+#include <sstream>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <openssl/ssl.h>
+
+namespace adb {
+namespace tls {
+
+namespace {
+
+// CA issuer identifier to distinguished embedded keys. Also has version
+// information appended to the end of the string (e.g. "AdbKey-0").
+static constexpr int kAdbKeyIdentifierNid = NID_organizationName;
+static constexpr char kAdbKeyIdentifierV0[] = "AdbKey-0";
+
+// Where we store the actual data
+static constexpr int kAdbKeyValueNid = NID_commonName;
+
+// TODO: Remove this once X509_NAME_add_entry_by_NID is fixed to use const unsigned char*
+// https://boringssl-review.googlesource.com/c/boringssl/+/39764
+int X509_NAME_add_entry_by_NID_const(X509_NAME* name, int nid, int type, const unsigned char* bytes,
+ int len, int loc, int set) {
+ return X509_NAME_add_entry_by_NID(name, nid, type, const_cast<unsigned char*>(bytes), len, loc,
+ set);
+}
+
+bool IsHexDigit(char c) {
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+}
+
+// Wrapper around X509_NAME_get_text_by_NID that first calculates the size
+// of the string. Returns empty string on failure.
+std::optional<std::string> GetX509NameTextByNid(X509_NAME* name, int nid) {
+ // |len| is the len of the text excluding the final null
+ int len = X509_NAME_get_text_by_NID(name, nid, nullptr, -1);
+ if (len <= 0) {
+ return std::nullopt;
+ }
+
+ // Include the space for the final null byte
+ std::vector<char> buf(len + 1, '\0');
+ CHECK(X509_NAME_get_text_by_NID(name, nid, buf.data(), buf.size()));
+ return std::make_optional(std::string(buf.data()));
+}
+
+} // namespace
+
+// Takes an encoded public key and generates a X509_NAME that can be used in
+// TlsConnection::SetClientCAList(), to allow the client to figure out which of
+// its keys it should try to use in the TLS handshake.
+bssl::UniquePtr<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key) {
+ // "O=AdbKey-0;CN=<key>;"
+ CHECK(!key.empty());
+
+ std::string identifier = kAdbKeyIdentifierV0;
+ bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+ CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyIdentifierNid, MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>(identifier.data()),
+ identifier.size(), -1, 0));
+
+ CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyValueNid, MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>(key.data()), key.size(),
+ -1, 0));
+ return name;
+}
+
+// Parses a CA issuer and returns the encoded key, if any.
+std::optional<std::string> ParseEncodedKeyFromCAIssuer(X509_NAME* issuer) {
+ CHECK(issuer);
+
+ auto buf = GetX509NameTextByNid(issuer, kAdbKeyIdentifierNid);
+ if (!buf) {
+ return std::nullopt;
+ }
+
+ // Check for supported versions
+ if (*buf == kAdbKeyIdentifierV0) {
+ return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
+ }
+ return std::nullopt;
+}
+
+std::string SHA256BitsToHexString(std::string_view sha256) {
+ CHECK_EQ(sha256.size(), static_cast<size_t>(SHA256_DIGEST_LENGTH));
+ std::stringstream ss;
+ auto* u8 = reinterpret_cast<const uint8_t*>(sha256.data());
+ ss << std::uppercase << std::setfill('0') << std::hex;
+ // Convert to hex-string representation
+ for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+ // Need to cast to something bigger than one byte, or
+ // stringstream will interpret it as a char value.
+ ss << std::setw(2) << static_cast<uint16_t>(u8[i]);
+ }
+ return ss.str();
+}
+
+std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str) {
+ if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) {
+ return std::nullopt;
+ }
+
+ std::string result;
+ for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+ auto bytestr = std::string(sha256_str.substr(i * 2, 2));
+ if (!IsHexDigit(bytestr[0]) || !IsHexDigit(bytestr[1])) {
+ LOG(ERROR) << "SHA256 string has invalid non-hex chars";
+ return std::nullopt;
+ }
+ result += static_cast<char>(std::stol(bytestr, nullptr, 16));
+ }
+ return result;
+}
+
+} // namespace tls
+} // namespace adb
diff --git a/adb/tls/include/adb/tls/adb_ca_list.h b/adb/tls/include/adb/tls/adb_ca_list.h
new file mode 100644
index 0000000..a1ab9a7
--- /dev/null
+++ b/adb/tls/include/adb/tls/adb_ca_list.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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 <openssl/base.h>
+#include <optional>
+#include <string>
+
+// These APIs is used to embed adbd's known public keys into client-allowed CA
+// issuer list that can indicate to the client which key to use.
+namespace adb {
+namespace tls {
+
+// Takes an encoded public key and generates a X509_NAME that can be used in
+// TlsConnection::SetClientCAList(), to allow the client to figure out which of
+// its keys it should try to use in the TLS handshake. This is guaranteed to
+// return a valid X509_NAME, given a non-empty key.
+bssl::UniquePtr<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key);
+
+// Parses a CA issuer and returns the encoded key, if any. On failure, returns
+// nullopt.
+std::optional<std::string> ParseEncodedKeyFromCAIssuer(X509_NAME* issuer);
+
+// Converts SHA256 bits to a hex string representation. |sha256| must be exactly
+// |SHA256_DIGEST_LENGTH| in size.
+std::string SHA256BitsToHexString(std::string_view sha256);
+
+// Converts a valid SHA256 hex string to the actual bits. Returns nullopt on
+// failure.
+std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str);
+
+} // namespace tls
+} // namespace adb
diff --git a/adb/tls/include/adb/tls/tls_connection.h b/adb/tls/include/adb/tls/tls_connection.h
new file mode 100644
index 0000000..bc5b98a
--- /dev/null
+++ b/adb/tls/include/adb/tls/tls_connection.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 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 <stddef.h>
+#include <stdint.h>
+
+#include <string_view>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+namespace adb {
+namespace tls {
+
+class TlsConnection {
+ public:
+ // This class will require both client and server to exchange valid
+ // certificates.
+ enum class Role {
+ Server,
+ Client,
+ };
+
+ enum class TlsError : uint8_t {
+ Success = 0,
+ // An error indicating that we rejected the peer's certificate.
+ CertificateRejected,
+ // An error indicating that the peer rejected our certificate.
+ PeerRejectedCertificate,
+ // Add more if needed
+ UnknownFailure,
+ };
+
+ using CertVerifyCb = std::function<int(X509_STORE_CTX*)>;
+ using SetCertCb = std::function<int(SSL*)>;
+
+ virtual ~TlsConnection() = default;
+
+ // Adds a trusted certificate to the list for the SSL connection.
+ // During the handshake phase, it will check the list of trusted certificates.
+ // The connection will fail if the peer's certificate is not in the list. If
+ // you would like to accept any certificate, use #SetCertVerifyCallback and
+ // set your callback to always return 1.
+ //
+ // Returns true if |cert| was successfully added, false otherwise.
+ virtual bool AddTrustedCertificate(std::string_view cert) = 0;
+
+ // Sets a custom certificate verify callback. |cb| must return 1 if the
+ // certificate is trusted. Otherwise, return 0 if not.
+ virtual void SetCertVerifyCallback(CertVerifyCb cb) = 0;
+
+ // Configures a client |ca_list| that the server sends to the client in the
+ // CertificateRequest message.
+ virtual void SetClientCAList(STACK_OF(X509_NAME) * ca_list) = 0;
+
+ // Sets a callback that will be called to select a certificate. See
+ // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_cert_cb
+ // for more details.
+ virtual void SetCertificateCallback(SetCertCb cb) = 0;
+
+ // Exports a value derived from the master secret used in the TLS
+ // connection. This value should be used alongside any PAKE to ensure the
+ // peer is the intended peer. |length| is the requested length for the
+ // keying material. This is only valid after |DoHandshake| succeeds.
+ virtual std::vector<uint8_t> ExportKeyingMaterial(size_t length) = 0;
+
+ // Enable client-side check on whether server accepted the handshake. In TLS
+ // 1.3, client will not know the server rejected the handshake until after
+ // performing a read operation. Basically, this will perform an
+ // SSL_peek right after the handshake and see whether that succeeds.
+ //
+ // IMPORTANT: this will only work if the protocol is a server-speaks-first
+ // type. Enabling this for the server is a no-op. This is disabled by
+ // default.
+ virtual void EnableClientPostHandshakeCheck(bool enable) = 0;
+
+ // Starts the handshake process. Returns TlsError::Success if handshake
+ // succeeded.
+ virtual TlsError DoHandshake() = 0;
+
+ // Reads |size| bytes and returns the data. The returned data has either
+ // size |size| or zero, in which case the read failed.
+ virtual std::vector<uint8_t> ReadFully(size_t size) = 0;
+
+ // Overloaded ReadFully method, which accepts a buffer for writing in.
+ // Returns true iff exactly |size| amount of data was written into |buf|,
+ // false otherwise.
+ virtual bool ReadFully(void* buf, size_t size) = 0;
+
+ // Writes |size| bytes. Returns true if all |size| bytes were read.
+ // Returns false otherwise.
+ virtual bool WriteFully(std::string_view data) = 0;
+
+ // Create a new TlsConnection instance. |cert| and |priv_key| cannot be
+ // empty.
+ static std::unique_ptr<TlsConnection> Create(Role role, std::string_view cert,
+ std::string_view priv_key,
+ android::base::borrowed_fd fd);
+
+ // Helper to set the certificate and key strings to a SSL client/server.
+ // Useful when in the set-certificate callback.
+ static bool SetCertAndKey(SSL* ssl, std::string_view cert_chain, std::string_view priv_key);
+
+ protected:
+ TlsConnection() = default;
+}; // TlsConnection
+
+} // namespace tls
+} // namespace adb
diff --git a/adb/tls/tests/Android.bp b/adb/tls/tests/Android.bp
new file mode 100644
index 0000000..198de58
--- /dev/null
+++ b/adb/tls/tests/Android.bp
@@ -0,0 +1,42 @@
+//
+// 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.
+//
+
+cc_test {
+ name: "adb_tls_connection_test",
+ srcs: [
+ "adb_ca_list_test.cpp",
+ "tls_connection_test.cpp",
+ ],
+
+ compile_multilib: "first",
+
+ shared_libs: [
+ "libbase",
+ "libcrypto",
+ "libcrypto_utils",
+ "libssl",
+ ],
+
+ // Let's statically link them so we don't have to install it onto the
+ // system image for testing.
+ static_libs: [
+ "libadb_crypto_static",
+ "libadb_protos_static",
+ "libadb_tls_connection_static",
+ ],
+
+ test_suites: ["device-tests"],
+}
diff --git a/adb/tls/tests/adb_ca_list_test.cpp b/adb/tls/tests/adb_ca_list_test.cpp
new file mode 100644
index 0000000..c727e5f
--- /dev/null
+++ b/adb/tls/tests/adb_ca_list_test.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 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 LOG_TAG "AdbCAListTest"
+
+#include <gtest/gtest.h>
+
+#include <adb/tls/adb_ca_list.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <openssl/ssl.h>
+
+namespace adb {
+namespace tls {
+
+class AdbCAListTest : public testing::Test {
+ protected:
+ virtual void SetUp() override {}
+
+ virtual void TearDown() override {}
+};
+
+TEST_F(AdbCAListTest, SHA256BitsToHexString_BadParam) {
+ // Should crash if not exactly SHA256_DIGEST_LENGTH size
+ ASSERT_DEATH(
+ {
+ // empty
+ std::string sha;
+ SHA256BitsToHexString(sha);
+ },
+ "");
+ ASSERT_DEATH(
+ {
+ std::string sha(1, 0x80);
+ SHA256BitsToHexString(sha);
+ },
+ "");
+ ASSERT_DEATH(
+ {
+ std::string sha(SHA256_DIGEST_LENGTH - 1, 0x80);
+ SHA256BitsToHexString(sha);
+ },
+ "");
+ ASSERT_DEATH(
+ {
+ std::string sha(SHA256_DIGEST_LENGTH + 1, 0x80);
+ SHA256BitsToHexString(sha);
+ },
+ "");
+}
+
+TEST_F(AdbCAListTest, SHA256HexStringToBits_BadParam) {
+ {
+ // empty
+ std::string sha_str;
+ auto res = SHA256HexStringToBits(sha_str);
+ EXPECT_FALSE(res.has_value());
+ }
+ {
+ std::string sha_str(1, 'a');
+ auto res = SHA256HexStringToBits(sha_str);
+ EXPECT_FALSE(res.has_value());
+ }
+ {
+ std::string sha_str(SHA256_DIGEST_LENGTH * 2 - 1, 'a');
+ auto res = SHA256HexStringToBits(sha_str);
+ EXPECT_FALSE(res.has_value());
+ }
+ {
+ std::string sha_str(SHA256_DIGEST_LENGTH * 2 + 1, 'a');
+ auto res = SHA256HexStringToBits(sha_str);
+ EXPECT_FALSE(res.has_value());
+ }
+ {
+ // Non-hex chars
+ std::string sha_str(SHA256_DIGEST_LENGTH * 2, 'a');
+ sha_str[32] = 'x';
+ auto res = SHA256HexStringToBits(sha_str);
+ EXPECT_FALSE(res.has_value());
+ }
+}
+
+TEST_F(AdbCAListTest, SHA256BitsToHexString_ValidParam) {
+ uint8_t ct = 0;
+ // Test every possible byte
+ std::vector<std::string> expectedStr = {
+ "000102030405060708090A0B0C0D0E0F"
+ "101112131415161718191A1B1C1D1E1F",
+
+ "202122232425262728292A2B2C2D2E2F"
+ "303132333435363738393A3B3C3D3E3F",
+
+ "404142434445464748494A4B4C4D4E4F"
+ "505152535455565758595A5B5C5D5E5F",
+
+ "606162636465666768696A6B6C6D6E6F"
+ "707172737475767778797A7B7C7D7E7F",
+
+ "808182838485868788898A8B8C8D8E8F"
+ "909192939495969798999A9B9C9D9E9F",
+
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
+ "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF",
+
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
+ "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF",
+
+ "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
+ "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
+ };
+
+ for (auto& expected : expectedStr) {
+ std::string sha;
+ while (sha.size() < SHA256_DIGEST_LENGTH) {
+ sha += ct++;
+ }
+
+ auto sha_str = SHA256BitsToHexString(sha);
+ EXPECT_EQ(expected, sha_str);
+
+ // try to convert back to bits
+ auto out_sha = SHA256HexStringToBits(sha_str);
+ ASSERT_TRUE(out_sha.has_value());
+ EXPECT_EQ(*out_sha, sha);
+ }
+}
+
+TEST_F(AdbCAListTest, CreateCAIssuerFromEncodedKey_EmptyKey) {
+ ASSERT_DEATH({ auto issuer = CreateCAIssuerFromEncodedKey(""); }, "");
+}
+
+TEST_F(AdbCAListTest, Smoke) {
+ {
+ std::string key =
+ "A45BC1FF6C89BF0E"
+ "65F9BA153FBC9876"
+ "4969B4113F1CF878"
+ "EEF9BF1C3F9C9227";
+ auto issuer = CreateCAIssuerFromEncodedKey(key);
+ ASSERT_NE(issuer, nullptr);
+
+ // Try to parse the encoded key out of the X509_NAME
+ auto out_key = ParseEncodedKeyFromCAIssuer(issuer.get());
+ ASSERT_TRUE(out_key.has_value());
+ EXPECT_EQ(key, *out_key);
+ }
+}
+
+} // namespace tls
+} // namespace adb
diff --git a/adb/tls/tests/tls_connection_test.cpp b/adb/tls/tests/tls_connection_test.cpp
new file mode 100644
index 0000000..27bc1c9
--- /dev/null
+++ b/adb/tls/tests/tls_connection_test.cpp
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2020 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 LOG_TAG "AdbWifiTlsConnectionTest"
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <adb/crypto/x509_generator.h>
+#include <adb/tls/adb_ca_list.h>
+#include <adb/tls/tls_connection.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <openssl/ssl.h>
+
+using namespace adb::crypto;
+
+namespace adb {
+namespace tls {
+
+using android::base::unique_fd;
+using TlsError = TlsConnection::TlsError;
+
+// Test X.509 certificates (RSA 2048)
+static const std::string kTestRsa2048ServerCert =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n"
+ "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NVoX\n"
+ "DTMwMDExODIyMjU1NVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n"
+ "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8E\n"
+ "2Ck9TfuKlz7wqWdMfknjZ1luFDp2IHxAUZzh/F6jeI2dOFGAjpeloSnGOE86FIaT\n"
+ "d1EvpyTh7nBwbrLZAA6XFZTo7Bl6BdNOQdqb2d2+cLEN0inFxqUIycevRtohUE1Y\n"
+ "FHM9fg442X1jOTWXjDZWeiqFWo95paAPhzm6pWqfJK1+YKfT1LsWZpYqJGGQE5pi\n"
+ "C3qOBYYgFpoXMxTYJNoZo3uOYEdM6upc8/vh15nMgIxX/ymJxEY5BHPpZPPWjXLg\n"
+ "BfzVaV9fUfv0JT4HQ4t2WvxC3cD/UsjWp2a6p454uUp2ENrANa+jRdRJepepg9D2\n"
+ "DKsx9L8zjc5Obqexrt0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
+ "Af8EBAMCAYYwHQYDVR0OBBYEFDFW+8GTErwoZN5Uu9KyY4QdGYKpMA0GCSqGSIb3\n"
+ "DQEBCwUAA4IBAQBCDEn6SHXGlq5TU7J8cg1kRPd9bsJW+0hDuKSq0REXDkl0PcBf\n"
+ "fy282Agg9enKPPKmnpeQjM1dmnxdM8tT8LIUbMl779i3fn6v9HJVB+yG4gmRFThW\n"
+ "c+AGlBnrIT820cX/gU3h3R3FTahfsq+1rrSJkEgHyuC0HYeRyveSckBdaEOLvx0S\n"
+ "toun+32JJl5hWydpUUZhE9Mbb3KHBRM2YYZZU9JeJ08Apjl+3lRUeMAUwI5fkAAu\n"
+ "z/1SqnuGL96bd8P5ixdkA1+rF8FPhodGcq9mQOuUGP9g5HOXjaNoJYvwVRUdLeGh\n"
+ "cP/ReOTwQIzM1K5a83p8cX8AGGYmM7dQp7ec\n"
+ "-----END CERTIFICATE-----\n";
+
+static const std::string kTestRsa2048ServerPrivKey =
+ "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvBNgpPU37ipc+\n"
+ "8KlnTH5J42dZbhQ6diB8QFGc4fxeo3iNnThRgI6XpaEpxjhPOhSGk3dRL6ck4e5w\n"
+ "cG6y2QAOlxWU6OwZegXTTkHam9ndvnCxDdIpxcalCMnHr0baIVBNWBRzPX4OONl9\n"
+ "Yzk1l4w2VnoqhVqPeaWgD4c5uqVqnyStfmCn09S7FmaWKiRhkBOaYgt6jgWGIBaa\n"
+ "FzMU2CTaGaN7jmBHTOrqXPP74deZzICMV/8picRGOQRz6WTz1o1y4AX81WlfX1H7\n"
+ "9CU+B0OLdlr8Qt3A/1LI1qdmuqeOeLlKdhDawDWvo0XUSXqXqYPQ9gyrMfS/M43O\n"
+ "Tm6nsa7dAgMBAAECggEAFCS2bPdUKIgjbzLgtHW+hT+J2hD20rcHdyAp+dNH/2vI\n"
+ "yLfDJHJA4chGMRondKA704oDw2bSJxxlG9t83326lB35yxPhye7cM8fqgWrK8PVl\n"
+ "tU22FhO1ZgeJvb9OeXWNxKZyDW9oOOJ8eazNXVMuEo+dFj7B6l3MXQyHJPL2mJDm\n"
+ "u9ofFLdypX+gJncVO0oW0FNJnEUn2MMwHDNlo7gc4WdQuidPkuZItKRGcB8TTGF3\n"
+ "Ka1/2taYdTQ4Aq//Z84LlFvE0zD3T4c8LwYYzOzD4gGGTXvft7vSHzIun1S8YLRS\n"
+ "dEKXdVjtaFhgH3uUe4j+1b/vMvSHeoGBNX/G88GD+wKBgQDWUYVlMVqc9HD2IeYi\n"
+ "EfBcNwAJFJkh51yAl5QbUBgFYgFJVkkS/EDxEGFPvEmI3/pAeQFHFY13BI466EPs\n"
+ "o8Z8UUwWDp+Z1MFHHKQKnFakbsZbZlbqjJ9VJsqpezbpWhMHTOmcG0dmE7rf0lyM\n"
+ "eQv9slBB8qp2NEUs5Of7f2C2bwKBgQDRDq4nUuMQF1hbjM05tGKSIwkobmGsLspv\n"
+ "TMhkM7fq4RpbFHmbNgsFqMhcqYZ8gY6/scv5KCuAZ4yHUkbqwf5h+QCwrJ4uJeUJ\n"
+ "ZgJfHus2mmcNSo8FwSkNoojIQtzcbJav7bs2K9VTuertk/i7IJLApU4FOZZ5pghN\n"
+ "EXu0CZF1cwKBgDWFGhjRIF29tU/h20R60llU6s9Zs3wB+NmsALJpZ/ZAKS4VPB5f\n"
+ "nCAXBRYSYRKrTCU5kpYbzb4BBzuysPOxWmnFK4j+keCqfrGxd02nCQP7HdHJVr8v\n"
+ "6sIq88UrHeVcNxBFprjzHvtgxfQK5k22FMZ/9wbhAKyQFQ5HA5+MiaxFAoGAIcZZ\n"
+ "ZIkDninnYIMS9OursShv5lRO+15j3i9tgKLKZ+wOMgDQ1L6acUOfezj4PU1BHr8+\n"
+ "0PYocQpJreMhCfRlgLaV4fVBaPs+UZJld7CrF5tCYudUy/01ALrtlk0XGZWBktK5\n"
+ "mDrksC4tQkzRtonAq9cJD9cJ9IVaefkFH0UcdvkCgYBpZj50VLeGhnHHBnkJRlV1\n"
+ "fV+/P6PAq6RtqjA6O9Qdaoj5V3w2d63aQcQXQLJjH2BBmtCIy47r04rFvZpbCxP7\n"
+ "NH/OnK9NHpk2ucRTe8TAnVbvF/TZzPJoIxAO/D3OWaW6df4R8en8u6GYzWFglAyT\n"
+ "sydGT8yfWD1FYUWgfrVRbg==\n"
+ "-----END PRIVATE KEY-----\n";
+
+static const std::string kTestRsa2048ClientCert =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n"
+ "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NloX\n"
+ "DTMwMDExODIyMjU1NlowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n"
+ "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI3a\n"
+ "EXh1S5FTbet7JVONswffRPaekdIK53cb8SnAbSO9X5OLA4zGwdkrBvDTsd96SKrp\n"
+ "JxmoNOE1DhbZh05KPlWAPkGKacjGWaz+S7biDOL0I6aaLbTlU/il1Ub9olPSBVUx\n"
+ "0nhdtEFgIOzddnP6/1KmyIIeRxS5lTKeg4avqUkZNXkz/wL1dHBFL7FNFf0SCcbo\n"
+ "tsub/deFbjZ27LTDN+SIBgFttTNqC5NTvoBAoMdyCOAgNYwaHO+fKiK3edfJieaw\n"
+ "7HD8qqmQxcpCtRlA8CUPj7GfR+WHiCJmlevhnkFXCo56R1BS0F4wuD4KPdSWt8gc\n"
+ "27ejH/9/z2cKo/6SLJMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
+ "Af8EBAMCAYYwHQYDVR0OBBYEFO/Mr5ygqqpyU/EHM9v7RDvcqaOkMA0GCSqGSIb3\n"
+ "DQEBCwUAA4IBAQAH33KMouzF2DYbjg90KDrDQr4rq3WfNb6P743knxdUFuvb+40U\n"
+ "QjC2OJZHkSexH7wfG/y6ic7vfCfF4clNs3QvU1lEjOZC57St8Fk7mdNdsWLwxEMD\n"
+ "uePFz0dvclSxNUHyCVMqNxddzQYzxiDWQRmXWrUBliMduQqEQelcxW2yDtg8bj+s\n"
+ "aMpR1ra9scaD4jzIZIIxLoOS9zBMuNRbgP217sZrniyGMhzoI1pZ/izN4oXpyH7O\n"
+ "THuaCzzRT3ph2f8EgmHSodz3ttgSf2DHzi/Ez1xUkk7NOlgNtmsxEdrM47+cC5ae\n"
+ "fIf2V+1o1JW8J7D11RmRbNPh3vfisueB4f88\n"
+ "-----END CERTIFICATE-----\n";
+
+static const std::string kTestRsa2048ClientPrivKey =
+ "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCN2hF4dUuRU23r\n"
+ "eyVTjbMH30T2npHSCud3G/EpwG0jvV+TiwOMxsHZKwbw07Hfekiq6ScZqDThNQ4W\n"
+ "2YdOSj5VgD5BimnIxlms/ku24gzi9COmmi205VP4pdVG/aJT0gVVMdJ4XbRBYCDs\n"
+ "3XZz+v9SpsiCHkcUuZUynoOGr6lJGTV5M/8C9XRwRS+xTRX9EgnG6LbLm/3XhW42\n"
+ "duy0wzfkiAYBbbUzaguTU76AQKDHcgjgIDWMGhzvnyoit3nXyYnmsOxw/KqpkMXK\n"
+ "QrUZQPAlD4+xn0flh4giZpXr4Z5BVwqOekdQUtBeMLg+Cj3UlrfIHNu3ox//f89n\n"
+ "CqP+kiyTAgMBAAECggEAAa64eP6ggCob1P3c73oayYPIbvRqiQdAFOrr7Vwu7zbr\n"
+ "z0rde+n6RU0mrpc+4NuzyPMtrOGQiatLbidJB5Cx3z8U00ovqbCl7PtcgorOhFKe\n"
+ "VEzihebCcYyQqbWQcKtpDMhOgBxRwFoXieJb6VGXfa96FAZalCWvXgOrTl7/BF2X\n"
+ "qMqIm9nJi+yS5tIO8VdOsOmrMWRH/b/ENUcef4WpLoxTXr0EEgyKWraeZ/hhXo1e\n"
+ "z29dZKqdr9wMsq11NPsRddwS94jnDkXTo+EQyWVTfB7gb6yyp07s8jysaDb21tVv\n"
+ "UXB9MRhDV1mOv0ncXfXZ4/+4A2UahmZaLDAVLaat4QKBgQDAVRredhGRGl2Nkic3\n"
+ "KvZCAfyxug788CgasBdEiouz19iCCwcgMIDwnq0s3/WM7h/laCamT2x38riYDnpq\n"
+ "rkYMfuVtU9CjEL9pTrdfwbIRhTwYNqADaPz2mXwQUhRXutE5TIdgxxC/a+ZTh0qN\n"
+ "S+vhTj/4hf0IZhMh5Nqj7IPExQKBgQC8zxEzhmSGjys0GuE6Wl6Doo2TpiR6vwvi\n"
+ "xPLU9lmIz5eca/Rd/eERioFQqeoIWDLzx52DXuz6rUoQhbJWz9hP3yqCwXD+pbNP\n"
+ "oDJqDDbCC4IMYEb0IK/PEPH+gIpnTjoFcW+ecKDFG7W5Lt05J8WsJsfOaJvMrOU+\n"
+ "dLXq3IgxdwKBgQC5RAFq0v6e8G+3hFaEHL0z3igkpt3zJf7rnj37hx2FMmDa+3Z0\n"
+ "umQp5B9af61PgL12xLmeMBmC/Wp1BlVDV/Yf6Uhk5Hyv5t0KuomHEtTNbbLyfAPs\n"
+ "5P/vJu/L5NS1oT4S3LX3MineyjgGs+bLbpub3z1dzutrYLADUSiPCK/xJQKBgBQt\n"
+ "nQ0Ao+Wtj1R2OvPdjJRM3wyUiPmFSWPm4HzaBx+T8AQLlYYmB9O0FbXlMtnJc0iS\n"
+ "YMcVcgYoVu4FG9YjSF7g3s4yljzgwJUV7c1fmMqMKE3iTDLy+1cJ3JLycdgwiArk\n"
+ "4KTyLHxkRbuQwpvFIF8RlfD9RQlOwQE3v+llwDhpAoGBAL6XG6Rp6mBoD2Ds5c9R\n"
+ "943yYgSUes3ji1SI9zFqeJtj8Ml/enuK1xu+8E/BxB0//+vgZsH6i3i8GFwygKey\n"
+ "CGJF8CbiHc3EJc3NQIIRXcni/CGacf0HwC6m+PGFDBIpA4H2iDpVvCSofxttQiq0\n"
+ "/Z7HXmXUvZHVyYi/QzX2Gahj\n"
+ "-----END PRIVATE KEY-----\n";
+
+static const std::string kTestRsa2048UnknownPrivKey =
+ "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrIhr+CS+6UI0w\n"
+ "CTaVzQAicKBe6X531LeQAGYx7j5RLHR1QIoJ0WCc5msmXKe2VzcWuLbVdTGAIP1H\n"
+ "mwbPqlbO4ioxeJhiDv+WPuLG8+j4Iw1Yqxt8cfohxjfvNmIQM8aF5hGyyaaTetDF\n"
+ "EYWONoYCBC4WnFWgYCPb8mzWXlhHE3F66GnHpc32zydPTg3ZurGvSsFf7fNY9yRw\n"
+ "8WtwPiI6mpRxt+n2bQUp+LZ+g/3rXLFPg8uWDGYG7IvLluWc9gR9lxjL64t6ryLU\n"
+ "2cm7eTfDgLw/B1F/wEgCJDnby1JgQ4rq6klJO3BR2ooUr/7T343y5njG5hQJreV7\n"
+ "5ZnSmRLZAgMBAAECggEABPrfeHZFuWkj7KqN+DbAmt/2aMCodZ3+7/20+528WkIe\n"
+ "CvXzdmTth+9UHagLWNzpnVuHdYd9JuZ+3F00aelh8JAIDIu++naHhUSj9ohtRoBF\n"
+ "oIeNK5ZJAj/Zi5hkauaIz8dxyyc/VdIYfm2bundXd7pNqYqH2tyFWp6PwH67GKlZ\n"
+ "1lC7o8gKAK8sz9g0Ctdoe+hDqAsvYFCW4EWDM2qboucSgn8g3E/Gux/KrpXVv7d0\n"
+ "PMQ60m+dyTOCMGqXIoDR3TAvQR7ex5sQ/QZSREdxKy878s/2FY4ktxtCUWlhrmcI\n"
+ "VKtrDOGEKwNoiMluf2635rsVq2e01XhQlmdxbRFU0QKBgQDjOhhD1m9duFTQ2b+J\n"
+ "Xfn6m8Rs7sZqO4Az7gLOWmD/vYWlK4n2nZsh6u5/cB1N+PA+ncvvV4yKJAlLHxbT\n"
+ "pVvfzJ/jbUsj/NJg/w7+KYC9gXgRmBonuG2gRZF/5Otdlza4vMcoSkqGjlGxJyzL\n"
+ "+9umEziN3tEYMRwipYvt7BgbUQKBgQDAzaXryJ3YD3jpecy/+fSnQvFjpyeDRqU1\n"
+ "KDA9nxN5tJN6bnKhUlMhy64SsgvVX9jUuN7cK+qYV0uzdBn6kIAJNLWTdbtH93+e\n"
+ "vNVgluR3jmixW4QfY9vfZKdXZbVGNc0DFMi1vJqgxTgQ5Mq5PxxxRL4FsAF840V1\n"
+ "Wu9uhU0NCQKBgBfjga2QG8E0oeYbHmHouWE5gxsYt09v1fifqzfalJwOZsCIpUaC\n"
+ "J08Xjd9kABC0fT14BXqyL5pOU5PMPvAdUF1k++JDGUU9TTjZV9AsuNYziFYBMa6/\n"
+ "WvcgmT1i6cO7JAuj/SQlO1SOHdSME8+WOO9q0eVIaZ8repPB58YprhchAoGBAJyR\n"
+ "Y8AJdkTSq7nNszvi245IioYGY8vzPo3gSOyBlesrfOfbcTMYC3JSWNXNyFZKM2br\n"
+ "ie75qtRzb4IXMlGLrq3LI/jPjnpuvjBF4HFDl9yOxO3iB3UGPrM2pb4PVhnh7s4l\n"
+ "vqf2tQsBnPn7EbVFTu+ch0NPHqYwWWNnqS/zCBMhAoGBAIkYjOE0iD9W2FXee6VL\n"
+ "iN8wDqlqsGEEtLvykIDmTmM+ZX5ftQuPo18khpE9wQKmJ5OpoVTYIP1UsJFBakgo\n"
+ "+dGaf6xVuPvmydNFqixlW3z227n4Px6GX7CXlCaAleTeItezli+dWf/9astwTA3x\n"
+ "IazYzsxUUpZFC4dJ1GhBn3y1\n"
+ "-----END PRIVATE KEY-----\n";
+
+static const std::string kTestRsa2048UnknownCert =
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n"
+ "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyNDE4MzMwNVoX\n"
+ "DTMwMDEyMTE4MzMwNVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n"
+ "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKsi\n"
+ "Gv4JL7pQjTAJNpXNACJwoF7pfnfUt5AAZjHuPlEsdHVAignRYJzmayZcp7ZXNxa4\n"
+ "ttV1MYAg/UebBs+qVs7iKjF4mGIO/5Y+4sbz6PgjDVirG3xx+iHGN+82YhAzxoXm\n"
+ "EbLJppN60MURhY42hgIELhacVaBgI9vybNZeWEcTcXroacelzfbPJ09ODdm6sa9K\n"
+ "wV/t81j3JHDxa3A+IjqalHG36fZtBSn4tn6D/etcsU+Dy5YMZgbsi8uW5Zz2BH2X\n"
+ "GMvri3qvItTZybt5N8OAvD8HUX/ASAIkOdvLUmBDiurqSUk7cFHaihSv/tPfjfLm\n"
+ "eMbmFAmt5XvlmdKZEtkCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
+ "Af8EBAMCAYYwHQYDVR0OBBYEFDtRSOm1ilhnq6bKN4qJ1ekK/PAkMA0GCSqGSIb3\n"
+ "DQEBCwUAA4IBAQAP6Q8/OxnBA3BO8oxKer0tjI4rZMefUhbAKUWXYjTTNEBm5//b\n"
+ "lVGP2RptO7bxj8w1L3rxsjmVcv2TqBOhrbJqvGVPE2ntoYlFhBBkRvmxuu1y5W9V\n"
+ "uJU7SF9lNmDXShTURULu3P8GdeT1HGeXzWQ4x7VhY9a3VIbmN5VxjB+3C6hYZxSs\n"
+ "DCpmidu/sR+n5Azlh6oqrhOxmv17PuF/ioTUsHd4y2Z41IvvO47oghxNDtboUUsg\n"
+ "LfsM1MOxVC9PqOfQphFU4i8owNIYzBMadDLw+1TSQj0ALqZVyc9Dq+WDFdz+JAE+\n"
+ "k7TkVU06UPGVSnLVzJeYwGCXQp3apBszY9vO\n"
+ "-----END CERTIFICATE-----\n";
+
+struct CAIssuerField {
+ int nid;
+ std::vector<uint8_t> val;
+};
+using CAIssuer = std::vector<CAIssuerField>;
+static std::vector<CAIssuer> kCAIssuers = {
+ {
+ {NID_commonName, {'a', 'b', 'c', 'd', 'e'}},
+ {NID_organizationName, {'d', 'e', 'f', 'g'}},
+ },
+ {
+ {NID_commonName, {'h', 'i', 'j', 'k', 'l', 'm'}},
+ {NID_countryName, {'n', 'o'}},
+ },
+};
+
+class AdbWifiTlsConnectionTest : public testing::Test {
+ protected:
+ virtual void SetUp() override {
+ android::base::Socketpair(SOCK_STREAM, &server_fd_, &client_fd_);
+ server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert,
+ kTestRsa2048ServerPrivKey, server_fd_);
+ client_ = TlsConnection::Create(TlsConnection::Role::Client, kTestRsa2048ClientCert,
+ kTestRsa2048ClientPrivKey, client_fd_);
+ ASSERT_NE(nullptr, server_);
+ ASSERT_NE(nullptr, client_);
+ }
+
+ virtual void TearDown() override {
+ WaitForClientConnection();
+ // Shutdown the SSL connection first.
+ server_.reset();
+ client_.reset();
+ }
+
+ bssl::UniquePtr<STACK_OF(X509_NAME)> GetCAIssuerList() {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
+ for (auto& issuer : kCAIssuers) {
+ bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+ for (auto& attr : issuer) {
+ CHECK(X509_NAME_add_entry_by_NID(name.get(), attr.nid, MBSTRING_ASC,
+ attr.val.data(), attr.val.size(), -1, 0));
+ }
+
+ CHECK(bssl::PushToStack(ret.get(), std::move(name)));
+ }
+
+ return ret;
+ }
+
+ void StartClientHandshakeAsync(TlsError expected) {
+ client_thread_ = std::thread([=]() { EXPECT_EQ(client_->DoHandshake(), expected); });
+ }
+
+ void WaitForClientConnection() {
+ if (client_thread_.joinable()) {
+ client_thread_.join();
+ }
+ }
+
+ unique_fd server_fd_;
+ unique_fd client_fd_;
+ const std::vector<uint8_t> msg_{0xff, 0xab, 0x32, 0xf6, 0x12, 0x56};
+ std::unique_ptr<TlsConnection> server_;
+ std::unique_ptr<TlsConnection> client_;
+ std::thread client_thread_;
+};
+
+TEST_F(AdbWifiTlsConnectionTest, InvalidCreationParams) {
+ // Verify that passing empty certificate/private key results in a crash.
+ ASSERT_DEATH(
+ {
+ server_ = TlsConnection::Create(TlsConnection::Role::Server, "",
+ kTestRsa2048ServerPrivKey, server_fd_);
+ },
+ "");
+ ASSERT_DEATH(
+ {
+ server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert,
+ "", server_fd_);
+ },
+ "");
+ ASSERT_DEATH(
+ {
+ client_ = TlsConnection::Create(TlsConnection::Role::Client, "",
+ kTestRsa2048ClientPrivKey, client_fd_);
+ },
+ "");
+ ASSERT_DEATH(
+ {
+ client_ = TlsConnection::Create(TlsConnection::Role::Client, kTestRsa2048ClientCert,
+ "", client_fd_);
+ },
+ "");
+}
+
+TEST_F(AdbWifiTlsConnectionTest, NoCertificateVerification) {
+ // Allow any certificate
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ StartClientHandshakeAsync(TlsError::Success);
+
+ // Handshake should succeed
+ ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Test client/server read and writes
+ client_thread_ = std::thread([&]() {
+ EXPECT_TRUE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ // Try with overloaded ReadFully
+ std::vector<uint8_t> buf(msg_.size());
+ ASSERT_TRUE(client_->ReadFully(buf.data(), msg_.size()));
+ EXPECT_EQ(buf, msg_);
+ });
+
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data, msg_);
+ EXPECT_TRUE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, NoTrustedCertificates) {
+ StartClientHandshakeAsync(TlsError::CertificateRejected);
+
+ // Handshake should not succeed
+ ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+ WaitForClientConnection();
+
+ // All writes and reads should fail
+ client_thread_ = std::thread([&]() {
+ // Client write, server read should fail
+ EXPECT_FALSE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+ });
+
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+ EXPECT_FALSE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates) {
+ // Add peer certificates
+ EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
+
+ StartClientHandshakeAsync(TlsError::Success);
+
+ // Handshake should succeed
+ ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // All read writes should succeed
+ client_thread_ = std::thread([&]() {
+ EXPECT_TRUE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data, msg_);
+ });
+
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data, msg_);
+ EXPECT_TRUE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates_ClientWrongCert) {
+ // Server trusts a certificate, client has the wrong certificate
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+ // Client accepts any certificate
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+ // Without enabling EnableClientPostHandshakeCheck(), DoHandshake() will
+ // succeed, because in TLS 1.3, the client doesn't get notified if the
+ // server rejected the certificate until a read operation is called.
+ StartClientHandshakeAsync(TlsError::Success);
+
+ // Handshake should fail for server, succeed for client
+ ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+ WaitForClientConnection();
+
+ // Client writes will succeed, everything else will fail.
+ client_thread_ = std::thread([&]() {
+ EXPECT_TRUE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+ });
+
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+ EXPECT_FALSE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, ExportKeyingMaterial) {
+ // Allow any certificate
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+ // Add peer certificates
+ EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
+
+ StartClientHandshakeAsync(TlsError::Success);
+
+ // Handshake should succeed
+ ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Verify the client and server's exported key material match.
+ const size_t key_size = 64;
+ auto client_key_material = client_->ExportKeyingMaterial(key_size);
+ ASSERT_FALSE(client_key_material.empty());
+ auto server_key_material = server_->ExportKeyingMaterial(key_size);
+ ASSERT_TRUE(!server_key_material.empty());
+ ASSERT_EQ(client_key_material.size(), key_size);
+ ASSERT_EQ(client_key_material, server_key_material);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientAcceptsServerRejects) {
+ // Client accepts all
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ // Server rejects all
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+ // Client handshake should succeed, because in TLS 1.3, client does not
+ // realize that the peer rejected the certificate until after a read
+ // operation.
+ StartClientHandshakeAsync(TlsError::Success);
+
+ // Server handshake should fail
+ ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientAcceptsServerRejects_PostHSCheck) {
+ // Client accepts all
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ // Client should now get a failure in the handshake
+ client_->EnableClientPostHandshakeCheck(true);
+ // Server rejects all
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+
+ // Client handshake should fail because server rejects everything
+ StartClientHandshakeAsync(TlsError::PeerRejectedCertificate);
+
+ // Server handshake should fail
+ ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientRejectsServerAccepts) {
+ // Client rejects all
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+ // Server accepts all
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ // Client handshake should fail
+ StartClientHandshakeAsync(TlsError::CertificateRejected);
+
+ // Server handshake should fail
+ ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientRejectsServerAccepts_PostHSCheck) {
+ // Client rejects all
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+ // This shouldn't affect the error types returned in the
+ // #SetCertVerifyCallback_ClientRejectsServerAccepts test, since
+ // the failure is still within the TLS 1.3 handshake.
+ client_->EnableClientPostHandshakeCheck(true);
+ // Server accepts all
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+ // Client handshake should fail
+ StartClientHandshakeAsync(TlsError::CertificateRejected);
+
+ // Server handshake should fail
+ ASSERT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, EnableClientPostHandshakeCheck_ClientWrongCert) {
+ client_->AddTrustedCertificate(kTestRsa2048ServerCert);
+ // client's DoHandshake() will fail if the server rejected the certificate
+ client_->EnableClientPostHandshakeCheck(true);
+
+ // Add peer certificates
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+
+ // Handshake should fail for client
+ StartClientHandshakeAsync(TlsError::PeerRejectedCertificate);
+
+ // Handshake should fail for server
+ ASSERT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+ WaitForClientConnection();
+
+ // All read writes should fail
+ client_thread_ = std::thread([&]() {
+ EXPECT_FALSE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+ });
+
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+ EXPECT_FALSE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Empty) {
+ // Setting an empty CA list should not crash
+ server_->SetClientCAList(nullptr);
+ ASSERT_DEATH(
+ {
+ // Client cannot use this API
+ client_->SetClientCAList(nullptr);
+ },
+ "");
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Smoke) {
+ auto bsslIssuerList = GetCAIssuerList();
+ server_->SetClientCAList(bsslIssuerList.get());
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+ client_thread_ = std::thread([&]() {
+ client_->SetCertificateCallback([&](SSL* ssl) -> int {
+ const STACK_OF(X509_NAME)* received = SSL_get_client_CA_list(ssl);
+ EXPECT_NE(received, nullptr);
+ const size_t num_names = sk_X509_NAME_num(received);
+ EXPECT_EQ(kCAIssuers.size(), num_names);
+
+ // Client initially registered with the wrong key. Let's change it
+ // here to verify this callback actually changes the client
+ // certificate to the right one.
+ EXPECT_TRUE(TlsConnection::SetCertAndKey(ssl, kTestRsa2048UnknownCert,
+ kTestRsa2048UnknownPrivKey));
+
+ const size_t buf_size = 256;
+ uint8_t buf[buf_size];
+ size_t idx = 0;
+ for (auto& issuer : kCAIssuers) {
+ auto* name = sk_X509_NAME_value(received, idx++);
+ for (auto& attr : issuer) {
+ EXPECT_EQ(X509_NAME_get_text_by_NID(name, attr.nid,
+ reinterpret_cast<char*>(buf), buf_size),
+ attr.val.size());
+ std::vector<uint8_t> out(buf, buf + attr.val.size());
+ EXPECT_EQ(out, attr.val);
+ }
+ }
+
+ return 1;
+ });
+ // Client handshake should succeed
+ ASSERT_EQ(client_->DoHandshake(), TlsError::Success);
+ });
+
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+ // Server handshake should succeed
+ ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
+ client_thread_.join();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_AdbCAList) {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list(sk_X509_NAME_new_null());
+ std::string keyhash = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ auto issuer = CreateCAIssuerFromEncodedKey(keyhash);
+ ASSERT_TRUE(bssl::PushToStack(ca_list.get(), std::move(issuer)));
+ server_->SetClientCAList(ca_list.get());
+ client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+ client_thread_ = std::thread([&]() {
+ client_->SetCertificateCallback([&](SSL* ssl) -> int {
+ // Client initially registered with a certificate that is not trusted by
+ // the server. Let's test that we can change the certificate to the
+ // trusted one here.
+ const STACK_OF(X509_NAME)* received = SSL_get_client_CA_list(ssl);
+ EXPECT_NE(received, nullptr);
+ const size_t num_names = sk_X509_NAME_num(received);
+ EXPECT_EQ(1, num_names);
+
+ auto* name = sk_X509_NAME_value(received, 0);
+ EXPECT_NE(name, nullptr);
+ auto enc_key = ParseEncodedKeyFromCAIssuer(name);
+ EXPECT_EQ(keyhash, enc_key);
+
+ return 1;
+ });
+ // Client handshake should succeed
+ ASSERT_EQ(client_->DoHandshake(), TlsError::Success);
+ });
+
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ // Server handshake should succeed
+ ASSERT_EQ(server_->DoHandshake(), TlsError::Success);
+ client_thread_.join();
+}
+} // namespace tls
+} // namespace adb
diff --git a/adb/tls/tls_connection.cpp b/adb/tls/tls_connection.cpp
new file mode 100644
index 0000000..853cdac
--- /dev/null
+++ b/adb/tls/tls_connection.cpp
@@ -0,0 +1,394 @@
+/*
+ * 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/tls/tls_connection.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+using android::base::borrowed_fd;
+
+namespace adb {
+namespace tls {
+
+namespace {
+
+static constexpr char kExportedKeyLabel[] = "adb-label";
+
+class TlsConnectionImpl : public TlsConnection {
+ public:
+ explicit TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key,
+ borrowed_fd fd);
+ ~TlsConnectionImpl() override;
+
+ bool AddTrustedCertificate(std::string_view cert) override;
+ void SetCertVerifyCallback(CertVerifyCb cb) override;
+ void SetCertificateCallback(SetCertCb cb) override;
+ void SetClientCAList(STACK_OF(X509_NAME) * ca_list) override;
+ std::vector<uint8_t> ExportKeyingMaterial(size_t length) override;
+ void EnableClientPostHandshakeCheck(bool enable) override;
+ TlsError DoHandshake() override;
+ std::vector<uint8_t> ReadFully(size_t size) override;
+ bool ReadFully(void* buf, size_t size) override;
+ bool WriteFully(std::string_view data) override;
+
+ static bssl::UniquePtr<EVP_PKEY> EvpPkeyFromPEM(std::string_view pem);
+ static bssl::UniquePtr<CRYPTO_BUFFER> BufferFromPEM(std::string_view pem);
+
+ private:
+ static int SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque);
+ static int SSLSetCertCb(SSL* ssl, void* opaque);
+
+ static bssl::UniquePtr<X509> X509FromBuffer(bssl::UniquePtr<CRYPTO_BUFFER> buffer);
+ static const char* SSLErrorString();
+ void Invalidate();
+ TlsError GetFailureReason(int err);
+ const char* RoleToString() { return role_ == Role::Server ? kServerRoleStr : kClientRoleStr; }
+
+ Role role_;
+ bssl::UniquePtr<EVP_PKEY> priv_key_;
+ bssl::UniquePtr<CRYPTO_BUFFER> cert_;
+
+ bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list_;
+ bssl::UniquePtr<SSL_CTX> ssl_ctx_;
+ bssl::UniquePtr<SSL> ssl_;
+ std::vector<bssl::UniquePtr<X509>> known_certificates_;
+ bool client_verify_post_handshake_ = false;
+
+ CertVerifyCb cert_verify_cb_;
+ SetCertCb set_cert_cb_;
+ borrowed_fd fd_;
+ static constexpr char kClientRoleStr[] = "[client]: ";
+ static constexpr char kServerRoleStr[] = "[server]: ";
+}; // TlsConnectionImpl
+
+TlsConnectionImpl::TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key,
+ borrowed_fd fd)
+ : role_(role), fd_(fd) {
+ CHECK(!cert.empty() && !priv_key.empty());
+ LOG(INFO) << RoleToString() << "Initializing adbwifi TlsConnection";
+ cert_ = BufferFromPEM(cert);
+ CHECK(cert_);
+ priv_key_ = EvpPkeyFromPEM(priv_key);
+ CHECK(priv_key_);
+}
+
+TlsConnectionImpl::~TlsConnectionImpl() {
+ // shutdown the SSL connection
+ if (ssl_ != nullptr) {
+ SSL_shutdown(ssl_.get());
+ }
+}
+
+// static
+const char* TlsConnectionImpl::SSLErrorString() {
+ auto sslerr = ERR_peek_last_error();
+ return ERR_reason_error_string(sslerr);
+}
+
+// static
+bssl::UniquePtr<EVP_PKEY> TlsConnectionImpl::EvpPkeyFromPEM(std::string_view pem) {
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem.data(), pem.size()));
+ return bssl::UniquePtr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
+// static
+bssl::UniquePtr<CRYPTO_BUFFER> TlsConnectionImpl::BufferFromPEM(std::string_view pem) {
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem.data(), pem.size()));
+ char* name = nullptr;
+ char* header = nullptr;
+ uint8_t* data = nullptr;
+ long data_len = 0;
+
+ if (!PEM_read_bio(bio.get(), &name, &header, &data, &data_len)) {
+ LOG(ERROR) << "Failed to read certificate";
+ return nullptr;
+ }
+ OPENSSL_free(name);
+ OPENSSL_free(header);
+
+ auto ret = bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(data, data_len, nullptr));
+ OPENSSL_free(data);
+ return ret;
+}
+
+// static
+bssl::UniquePtr<X509> TlsConnectionImpl::X509FromBuffer(bssl::UniquePtr<CRYPTO_BUFFER> buffer) {
+ if (!buffer) {
+ return nullptr;
+ }
+ return bssl::UniquePtr<X509>(X509_parse_from_buffer(buffer.get()));
+}
+
+// static
+int TlsConnectionImpl::SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque) {
+ auto* p = reinterpret_cast<TlsConnectionImpl*>(opaque);
+ return p->cert_verify_cb_(ctx);
+}
+
+// static
+int TlsConnectionImpl::SSLSetCertCb(SSL* ssl, void* opaque) {
+ auto* p = reinterpret_cast<TlsConnectionImpl*>(opaque);
+ return p->set_cert_cb_(ssl);
+}
+
+bool TlsConnectionImpl::AddTrustedCertificate(std::string_view cert) {
+ // Create X509 buffer from the certificate string
+ auto buf = X509FromBuffer(BufferFromPEM(cert));
+ if (buf == nullptr) {
+ LOG(ERROR) << RoleToString() << "Failed to create a X509 buffer for the certificate.";
+ return false;
+ }
+ known_certificates_.push_back(std::move(buf));
+ return true;
+}
+
+void TlsConnectionImpl::SetCertVerifyCallback(CertVerifyCb cb) {
+ cert_verify_cb_ = cb;
+}
+
+void TlsConnectionImpl::SetCertificateCallback(SetCertCb cb) {
+ set_cert_cb_ = cb;
+}
+
+void TlsConnectionImpl::SetClientCAList(STACK_OF(X509_NAME) * ca_list) {
+ CHECK(role_ == Role::Server);
+ ca_list_.reset(ca_list != nullptr ? SSL_dup_CA_list(ca_list) : nullptr);
+}
+
+std::vector<uint8_t> TlsConnectionImpl::ExportKeyingMaterial(size_t length) {
+ if (ssl_.get() == nullptr) {
+ return {};
+ }
+
+ std::vector<uint8_t> out(length);
+ if (SSL_export_keying_material(ssl_.get(), out.data(), out.size(), kExportedKeyLabel,
+ sizeof(kExportedKeyLabel), nullptr, 0, false) == 0) {
+ return {};
+ }
+ return out;
+}
+
+void TlsConnectionImpl::EnableClientPostHandshakeCheck(bool enable) {
+ client_verify_post_handshake_ = enable;
+}
+
+TlsConnection::TlsError TlsConnectionImpl::GetFailureReason(int err) {
+ switch (ERR_GET_REASON(err)) {
+ case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+ case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
+ case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+ case SSL_R_TLSV1_ALERT_ACCESS_DENIED:
+ case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+ case SSL_R_TLSV1_CERTIFICATE_REQUIRED:
+ return TlsError::PeerRejectedCertificate;
+ case SSL_R_CERTIFICATE_VERIFY_FAILED:
+ return TlsError::CertificateRejected;
+ default:
+ return TlsError::UnknownFailure;
+ }
+}
+
+TlsConnection::TlsError TlsConnectionImpl::DoHandshake() {
+ LOG(INFO) << RoleToString() << "Starting adbwifi tls handshake";
+ ssl_ctx_.reset(SSL_CTX_new(TLS_method()));
+ // TODO: Remove set_max_proto_version() once external/boringssl is updated
+ // past
+ // https://boringssl.googlesource.com/boringssl/+/58d56f4c59969a23e5f52014e2651c76fea2f877
+ if (ssl_ctx_.get() == nullptr ||
+ !SSL_CTX_set_min_proto_version(ssl_ctx_.get(), TLS1_3_VERSION) ||
+ !SSL_CTX_set_max_proto_version(ssl_ctx_.get(), TLS1_3_VERSION)) {
+ LOG(ERROR) << RoleToString() << "Failed to create SSL context";
+ return TlsError::UnknownFailure;
+ }
+
+ // Register user-supplied known certificates
+ for (auto const& cert : known_certificates_) {
+ if (X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx_.get()), cert.get()) == 0) {
+ LOG(ERROR) << RoleToString() << "Unable to add certificates into the X509_STORE";
+ return TlsError::UnknownFailure;
+ }
+ }
+
+ // Custom certificate verification
+ if (cert_verify_cb_) {
+ SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), SSLSetCertVerifyCb, this);
+ }
+
+ // set select certificate callback, if any.
+ if (set_cert_cb_) {
+ SSL_CTX_set_cert_cb(ssl_ctx_.get(), SSLSetCertCb, this);
+ }
+
+ // Server-allowed client CA list
+ if (ca_list_ != nullptr) {
+ bssl::UniquePtr<STACK_OF(X509_NAME)> names(SSL_dup_CA_list(ca_list_.get()));
+ SSL_CTX_set_client_CA_list(ssl_ctx_.get(), names.release());
+ }
+
+ // Register our certificate and private key.
+ std::vector<CRYPTO_BUFFER*> cert_chain = {
+ cert_.get(),
+ };
+ if (!SSL_CTX_set_chain_and_key(ssl_ctx_.get(), cert_chain.data(), cert_chain.size(),
+ priv_key_.get(), nullptr)) {
+ LOG(ERROR) << RoleToString()
+ << "Unable to register the certificate chain file and private key ["
+ << SSLErrorString() << "]";
+ Invalidate();
+ return TlsError::UnknownFailure;
+ }
+
+ SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+
+ // Okay! Let's try to do the handshake!
+ ssl_.reset(SSL_new(ssl_ctx_.get()));
+ if (!SSL_set_fd(ssl_.get(), fd_.get())) {
+ LOG(ERROR) << RoleToString() << "SSL_set_fd failed. [" << SSLErrorString() << "]";
+ return TlsError::UnknownFailure;
+ }
+
+ switch (role_) {
+ case Role::Server:
+ SSL_set_accept_state(ssl_.get());
+ break;
+ case Role::Client:
+ SSL_set_connect_state(ssl_.get());
+ break;
+ }
+ if (SSL_do_handshake(ssl_.get()) != 1) {
+ LOG(ERROR) << RoleToString() << "Handshake failed in SSL_accept/SSL_connect ["
+ << SSLErrorString() << "]";
+ auto sslerr = ERR_get_error();
+ Invalidate();
+ return GetFailureReason(sslerr);
+ }
+
+ if (client_verify_post_handshake_ && role_ == Role::Client) {
+ uint8_t check;
+ // Try to peek one byte for any failures. This assumes on success that
+ // the server actually sends something.
+ if (SSL_peek(ssl_.get(), &check, 1) <= 0) {
+ LOG(ERROR) << RoleToString() << "Post-handshake SSL_peek failed [" << SSLErrorString()
+ << "]";
+ auto sslerr = ERR_get_error();
+ Invalidate();
+ return GetFailureReason(sslerr);
+ }
+ }
+
+ LOG(INFO) << RoleToString() << "Handshake succeeded.";
+ return TlsError::Success;
+}
+
+void TlsConnectionImpl::Invalidate() {
+ ssl_.reset();
+ ssl_ctx_.reset();
+}
+
+std::vector<uint8_t> TlsConnectionImpl::ReadFully(size_t size) {
+ std::vector<uint8_t> buf(size);
+ if (!ReadFully(buf.data(), buf.size())) {
+ return {};
+ }
+
+ return buf;
+}
+
+bool TlsConnectionImpl::ReadFully(void* buf, size_t size) {
+ CHECK_GT(size, 0U);
+ if (!ssl_) {
+ LOG(ERROR) << RoleToString() << "Tried to read on a null SSL connection";
+ return false;
+ }
+
+ size_t offset = 0;
+ uint8_t* p8 = reinterpret_cast<uint8_t*>(buf);
+ while (size > 0) {
+ int bytes_read =
+ SSL_read(ssl_.get(), p8 + offset, std::min(static_cast<size_t>(INT_MAX), size));
+ if (bytes_read <= 0) {
+ LOG(ERROR) << RoleToString() << "SSL_read failed [" << SSLErrorString() << "]";
+ return false;
+ }
+ size -= bytes_read;
+ offset += bytes_read;
+ }
+ return true;
+}
+
+bool TlsConnectionImpl::WriteFully(std::string_view data) {
+ CHECK(!data.empty());
+ if (!ssl_) {
+ LOG(ERROR) << RoleToString() << "Tried to read on a null SSL connection";
+ return false;
+ }
+
+ while (!data.empty()) {
+ int bytes_out = SSL_write(ssl_.get(), data.data(),
+ std::min(static_cast<size_t>(INT_MAX), data.size()));
+ if (bytes_out <= 0) {
+ LOG(ERROR) << RoleToString() << "SSL_write failed [" << SSLErrorString() << "]";
+ return false;
+ }
+ data = data.substr(bytes_out);
+ }
+ return true;
+}
+} // namespace
+
+// static
+std::unique_ptr<TlsConnection> TlsConnection::Create(TlsConnection::Role role,
+ std::string_view cert,
+ std::string_view priv_key, borrowed_fd fd) {
+ CHECK(!cert.empty());
+ CHECK(!priv_key.empty());
+
+ return std::make_unique<TlsConnectionImpl>(role, cert, priv_key, fd);
+}
+
+// static
+bool TlsConnection::SetCertAndKey(SSL* ssl, std::string_view cert, std::string_view priv_key) {
+ CHECK(ssl);
+ // Note: declaring these in local scope is okay because
+ // SSL_set_chain_and_key will increase the refcount (bssl::UpRef).
+ auto x509_cert = TlsConnectionImpl::BufferFromPEM(cert);
+ auto evp_pkey = TlsConnectionImpl::EvpPkeyFromPEM(priv_key);
+ if (x509_cert == nullptr || evp_pkey == nullptr) {
+ return false;
+ }
+
+ std::vector<CRYPTO_BUFFER*> cert_chain = {
+ x509_cert.get(),
+ };
+ if (!SSL_set_chain_and_key(ssl, cert_chain.data(), cert_chain.size(), evp_pkey.get(),
+ nullptr)) {
+ LOG(ERROR) << "SSL_set_chain_and_key failed";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace tls
+} // namespace adb
diff --git a/base/Android.bp b/base/Android.bp
index a32959b..25c74f2 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -128,6 +128,10 @@
static_libs: ["fmtlib"],
whole_static_libs: ["fmtlib"],
export_static_lib_headers: ["fmtlib"],
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
}
cc_library_static {
diff --git a/base/include/android-base/result.h b/base/include/android-base/result.h
index 4a59552..5e65876 100644
--- a/base/include/android-base/result.h
+++ b/base/include/android-base/result.h
@@ -191,11 +191,6 @@
return ErrorCode(code, args...);
}
-// TODO(tomcherry): Remove this once we've removed all `using android::base::Errorf` and `using
-// android::base::ErrnoErrorf` lines.
-enum Errorf {};
-enum ErrnoErrorf {};
-
template <typename T, typename... Args>
inline Error ErrorfImpl(const T&& fmt, const Args&... args) {
return Error(false, ErrorCode(0, args...), fmt::format(fmt, args...));
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 9ffe5dd..a9c1676 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -870,6 +870,7 @@
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
+const char last_reboot_reason_file[] = LAST_REBOOT_REASON_FILE;
const char last_last_reboot_reason_property[] = "sys.boot.reason.last";
constexpr size_t history_reboot_reason_size = 4;
const char history_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY ".history";
@@ -1059,7 +1060,9 @@
if (isBluntRebootReason(ret)) {
// Content buffer no longer will have console data. Beware if more
// checks added below, that depend on parsing console content.
- content = android::base::GetProperty(last_reboot_reason_property, "");
+ if (!android::base::ReadFileToString(last_reboot_reason_file, &content)) {
+ content = android::base::GetProperty(last_reboot_reason_property, "");
+ }
transformReason(content);
// Anything in last is better than 'super-blunt' reboot or shutdown.
@@ -1233,7 +1236,10 @@
// Record the scrubbed system_boot_reason to the property
BootReasonAddToHistory(system_boot_reason);
// Shift last_reboot_reason_property to last_last_reboot_reason_property
- auto last_boot_reason = android::base::GetProperty(last_reboot_reason_property, "");
+ std::string last_boot_reason;
+ if (!android::base::ReadFileToString(last_reboot_reason_file, &last_boot_reason)) {
+ last_boot_reason = android::base::GetProperty(last_reboot_reason_property, "");
+ }
if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
last_boot_reason = system_boot_reason;
} else {
@@ -1241,6 +1247,7 @@
}
android::base::SetProperty(last_last_reboot_reason_property, last_boot_reason);
android::base::SetProperty(last_reboot_reason_property, "");
+ unlink(last_reboot_reason_file);
}
// Gets the boot time offset. This is useful when Android is running in a
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index b27126b..3a6eb2d 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -234,10 +234,11 @@
LINFO << "Running " << E2FSCK_BIN << " on " << realpath(blk_device);
if (should_force_check(*fs_stat)) {
ret = logwrap_fork_execvp(ARRAY_SIZE(e2fsck_forced_argv), e2fsck_forced_argv,
- &status, false, LOG_KLOG | LOG_FILE, true, FSCK_LOG_FILE);
+ &status, false, LOG_KLOG | LOG_FILE, false,
+ FSCK_LOG_FILE);
} else {
ret = logwrap_fork_execvp(ARRAY_SIZE(e2fsck_argv), e2fsck_argv, &status, false,
- LOG_KLOG | LOG_FILE, true, FSCK_LOG_FILE);
+ LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
}
if (ret < 0) {
@@ -256,11 +257,11 @@
if (should_force_check(*fs_stat)) {
LINFO << "Running " << F2FS_FSCK_BIN << " -f " << realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
- &status, false, LOG_KLOG | LOG_FILE, true, FSCK_LOG_FILE);
+ &status, false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
} else {
LINFO << "Running " << F2FS_FSCK_BIN << " -a " << realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
- LOG_KLOG | LOG_FILE, true, FSCK_LOG_FILE);
+ LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
}
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
@@ -338,7 +339,7 @@
static bool run_tune2fs(const char* argv[], int argc) {
int ret;
- ret = logwrap_fork_execvp(argc, argv, nullptr, false, LOG_KLOG, true, nullptr);
+ ret = logwrap_fork_execvp(argc, argv, nullptr, false, LOG_KLOG, false, nullptr);
return ret == 0;
}
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index a8c2cc1..5aefb7e 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -86,8 +86,8 @@
mke2fs_args.push_back(fs_blkdev.c_str());
mke2fs_args.push_back(size_str.c_str());
- rc = logwrap_fork_execvp(mke2fs_args.size(), mke2fs_args.data(), nullptr, false, LOG_KLOG, true,
- nullptr);
+ rc = logwrap_fork_execvp(mke2fs_args.size(), mke2fs_args.data(), nullptr, false, LOG_KLOG,
+ false, nullptr);
if (rc) {
LERROR << "mke2fs returned " << rc;
return rc;
@@ -97,7 +97,7 @@
"/system/bin/e2fsdroid", "-e", "-a", fs_mnt_point.c_str(), fs_blkdev.c_str(), nullptr};
rc = logwrap_fork_execvp(arraysize(e2fsdroid_args), e2fsdroid_args, nullptr, false, LOG_KLOG,
- true, nullptr);
+ false, nullptr);
if (rc) {
LERROR << "e2fsdroid returned " << rc;
}
@@ -135,7 +135,7 @@
args.push_back(fs_blkdev.c_str());
args.push_back(size_str.c_str());
- return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, true, nullptr);
+ return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, false, nullptr);
}
int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index c55e532..83c43c6 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -277,9 +277,9 @@
} else if (StartsWith(flag, "keydirectory=")) {
// The metadata flag is followed by an = and the directory for the keys.
entry->metadata_key_dir = arg;
- } else if (StartsWith(flag, "metadata_cipher=")) {
- // Specify the cipher to use for metadata encryption
- entry->metadata_cipher = arg;
+ } else if (StartsWith(flag, "metadata_encryption=")) {
+ // Specify the cipher and flags to use for metadata encryption
+ entry->metadata_encryption = arg;
} else if (StartsWith(flag, "sysfs_path=")) {
// The path to trigger device gc by idle-maint of vold.
entry->sysfs_path = arg;
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 93bba68..24cbad7 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -80,9 +80,13 @@
return &(*it);
}
+auto verbose = false;
+
void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
const char* file, unsigned int line, const char* message) {
- fprintf(stderr, "%s\n", message);
+ if (verbose || severity == android::base::ERROR || message[0] != '[') {
+ fprintf(stderr, "%s\n", message);
+ }
static auto logd = android::base::LogdLogger();
logd(id, severity, tag, file, line, message);
}
@@ -131,10 +135,14 @@
{"fstab", required_argument, nullptr, 'T'},
{"help", no_argument, nullptr, 'h'},
{"reboot", no_argument, nullptr, 'R'},
+ {"verbose", no_argument, nullptr, 'v'},
{0, 0, nullptr, 0},
};
- for (int opt; (opt = ::getopt_long(argc, argv, "hRT:", longopts, nullptr)) != -1;) {
+ for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
switch (opt) {
+ case 'h':
+ usage(SUCCESS);
+ break;
case 'R':
can_reboot = true;
break;
@@ -145,13 +153,13 @@
}
fstab_file = optarg;
break;
+ case 'v':
+ verbose = true;
+ break;
default:
LOG(ERROR) << "Bad Argument -" << char(opt);
usage(BADARG);
break;
- case 'h':
- usage(SUCCESS);
- break;
}
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 4dc09c1..087138e 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -38,7 +38,7 @@
std::string fs_options;
std::string key_loc;
std::string metadata_key_dir;
- std::string metadata_cipher;
+ std::string metadata_encryption;
off64_t length = 0;
std::string label;
int partnum = -1;
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index d7b689e..6461788 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -280,6 +280,7 @@
extra_argv.emplace_back("allow_discards");
extra_argv.emplace_back("sector_size:4096");
extra_argv.emplace_back("iv_large_sectors");
+ if (is_hw_wrapped_) extra_argv.emplace_back("wrappedkey_v0");
}
if (!extra_argv.empty()) {
argv.emplace_back(std::to_string(extra_argv.size()));
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index affdd29..67af59a 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -526,13 +526,18 @@
bool is_legacy;
ASSERT_TRUE(DmTargetDefaultKey::IsLegacy(&is_legacy));
// set_dun only in the non-is_legacy case
- DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0,
- is_legacy, !is_legacy);
+ DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0);
+ if (is_legacy) {
+ target.SetIsLegacy();
+ } else {
+ target.SetSetDun();
+ }
ASSERT_EQ(target.name(), "default-key");
ASSERT_TRUE(target.Valid());
if (is_legacy) {
ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
} else {
+ // TODO: Add case for wrapped key enabled
ASSERT_EQ(target.GetParameterString(),
"AES-256-XTS abcdef0123456789 0 /dev/loop0 0 3 allow_discards sector_size:4096 "
"iv_large_sectors");
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index e3dd92b..d2e50d3 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -280,20 +280,20 @@
class DmTargetDefaultKey final : public DmTarget {
public:
DmTargetDefaultKey(uint64_t start, uint64_t length, const std::string& cipher,
- const std::string& key, const std::string& blockdev, uint64_t start_sector,
- bool is_legacy, bool set_dun)
+ const std::string& key, const std::string& blockdev, uint64_t start_sector)
: DmTarget(start, length),
cipher_(cipher),
key_(key),
blockdev_(blockdev),
- start_sector_(start_sector),
- is_legacy_(is_legacy),
- set_dun_(set_dun) {}
+ start_sector_(start_sector) {}
std::string name() const override { return name_; }
bool Valid() const override;
std::string GetParameterString() const override;
static bool IsLegacy(bool* result);
+ void SetIsLegacy() { is_legacy_ = true; }
+ void SetSetDun() { set_dun_ = true; }
+ void SetWrappedKeyV0() { is_hw_wrapped_ = true; }
private:
static const std::string name_;
@@ -301,8 +301,9 @@
std::string key_;
std::string blockdev_;
uint64_t start_sector_;
- bool is_legacy_;
- bool set_dun_;
+ bool is_legacy_ = false;
+ bool set_dun_ = false;
+ bool is_hw_wrapped_ = false;
};
} // namespace dm
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index adfee1d..d274ba4 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -72,6 +72,7 @@
"android/snapshot/snapshot.proto",
"device_info.cpp",
"snapshot.cpp",
+ "snapshot_stats.cpp",
"snapshot_metadata_updater.cpp",
"partition_cow_creator.cpp",
"return.cpp",
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index a3a518d..2ac0c44 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -131,3 +131,13 @@
// Sectors allocated for metadata in all the snapshot devices.
uint64 metadata_sectors = 4;
}
+
+// Next: 2
+message SnapshotMergeReport {
+ // Status of the update after the merge attempts.
+ UpdateState state = 1;
+
+ // Number of reboots that occurred after issuing and before completeing the
+ // merge of all the snapshot devices.
+ int32 resume_count = 2;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index ed92dd7..b440c71 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -91,6 +91,8 @@
using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
using FiemapStatus = android::fiemap::FiemapStatus;
+ friend class SnapshotMergeStats;
+
public:
// Dependency injection for testing.
class IDeviceInfo {
@@ -177,7 +179,7 @@
// - Unverified if called on the source slot
// - MergeCompleted if merge is completed
// - other states indicating an error has occurred
- UpdateState InitiateMergeAndWait();
+ UpdateState InitiateMergeAndWait(SnapshotMergeReport* report = nullptr);
// Wait for the merge if rebooted into the new slot. Does NOT initiate a
// merge. If the merge has not been initiated (but should be), wait.
@@ -395,6 +397,10 @@
bool WriteSnapshotUpdateStatus(LockedFile* file, const SnapshotUpdateStatus& status);
std::string GetStateFilePath() const;
+ // Interact with /metadata/ota/merge_state.
+ // This file contains information related to the snapshot merge process.
+ std::string GetMergeStateFilePath() const;
+
// Helpers for merging.
bool SwitchSnapshotToMerge(LockedFile* lock, const std::string& name);
bool RewriteSnapshotDeviceTable(const std::string& dm_name);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index ba53615..2fe06fb 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -46,6 +46,7 @@
#include "device_info.h"
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
+#include "snapshot_stats.h"
#include "utility.h"
namespace android {
@@ -1739,6 +1740,10 @@
return metadata_dir_ + "/state"s;
}
+std::string SnapshotManager::GetMergeStateFilePath() const {
+ return metadata_dir_ + "/merge_state"s;
+}
+
std::string SnapshotManager::GetLockPath() const {
return metadata_dir_;
}
@@ -2383,7 +2388,7 @@
return AutoUnmountDevice::New(device_->GetMetadataDir());
}
-UpdateState SnapshotManager::InitiateMergeAndWait() {
+UpdateState SnapshotManager::InitiateMergeAndWait(SnapshotMergeReport* stats_report) {
{
auto lock = LockExclusive();
// Sync update state from file with bootloader.
@@ -2393,6 +2398,8 @@
}
}
+ SnapshotMergeStats merge_stats(*this);
+
unsigned int last_progress = 0;
auto callback = [&]() -> void {
double progress;
@@ -2405,7 +2412,9 @@
LOG(INFO) << "Waiting for any previous merge request to complete. "
<< "This can take up to several minutes.";
+ merge_stats.Resume();
auto state = ProcessUpdateState(callback);
+ merge_stats.set_state(state);
if (state == UpdateState::None) {
LOG(INFO) << "Can't find any snapshot to merge.";
return state;
@@ -2415,6 +2424,11 @@
LOG(INFO) << "Cannot merge until device reboots.";
return state;
}
+
+ // This is the first snapshot merge that is requested after OTA. We can
+ // initialize the merge duration statistics.
+ merge_stats.Start();
+
if (!InitiateMerge()) {
LOG(ERROR) << "Failed to initiate merge.";
return state;
@@ -2423,9 +2437,13 @@
LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
last_progress = 0;
state = ProcessUpdateState(callback);
+ merge_stats.set_state(state);
}
LOG(INFO) << "Merge finished with state \"" << state << "\".";
+ if (stats_report) {
+ *stats_report = merge_stats.GetReport();
+ }
return state;
}
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
new file mode 100644
index 0000000..c48509e
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -0,0 +1,80 @@
+// Copyright (C) 2020 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 "snapshot_stats.h"
+
+#include <sstream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include "utility.h"
+
+namespace android {
+namespace snapshot {
+
+SnapshotMergeStats::SnapshotMergeStats(SnapshotManager& parent) : parent_(parent) {
+ init_time_ = std::chrono::steady_clock::now();
+}
+
+SnapshotMergeStats::~SnapshotMergeStats() {
+ std::string error;
+ auto file_path = parent_.GetMergeStateFilePath();
+ if (!android::base::RemoveFileIfExists(file_path, &error)) {
+ LOG(ERROR) << "Failed to remove merge statistics file " << file_path << ": " << error;
+ return;
+ }
+}
+
+void SnapshotMergeStats::Start() {
+ SnapshotMergeReport report;
+ report.set_resume_count(0);
+ report.set_state(UpdateState::None);
+
+ std::string contents;
+ if (!report.SerializeToString(&contents)) {
+ LOG(ERROR) << "Unable to serialize SnapshotMergeStats.";
+ return;
+ }
+ auto file_path = parent_.GetMergeStateFilePath();
+ if (!WriteStringToFileAtomic(contents, file_path)) {
+ PLOG(ERROR) << "Could not write to merge statistics file";
+ return;
+ }
+}
+
+void SnapshotMergeStats::Resume() {
+ std::string contents;
+ if (!android::base::ReadFileToString(parent_.GetMergeStateFilePath(), &contents)) {
+ PLOG(INFO) << "Read merge statistics file failed";
+ return;
+ }
+
+ if (!report_.ParseFromString(contents)) {
+ LOG(ERROR) << "Unable to parse merge statistics file as SnapshotMergeReport";
+ return;
+ }
+
+ report_.set_resume_count(report_.resume_count() + 1);
+}
+
+void SnapshotMergeStats::set_state(android::snapshot::UpdateState state) {
+ report_.set_state(state);
+}
+
+SnapshotMergeReport SnapshotMergeStats::GetReport() {
+ return report_;
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/snapshot_stats.h
new file mode 100644
index 0000000..1ca9156
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_stats.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2020 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 <chrono>
+
+#include <android/snapshot/snapshot.pb.h>
+#include <libsnapshot/snapshot.h>
+
+namespace android {
+namespace snapshot {
+
+class SnapshotMergeStats {
+ public:
+ SnapshotMergeStats(SnapshotManager& parent);
+ ~SnapshotMergeStats();
+ void Start();
+ void Resume();
+ void set_state(android::snapshot::UpdateState state);
+ SnapshotMergeReport GetReport();
+
+ private:
+ const SnapshotManager& parent_;
+ SnapshotMergeReport report_;
+ std::chrono::time_point<std::chrono::steady_clock> init_time_;
+ std::chrono::time_point<std::chrono::steady_clock> end_time_;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index d87274d..5d2840f 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1767,6 +1767,7 @@
protected:
void SetUp() override {
if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
+ GTEST_SKIP() << "WIP failure b/149738928";
SnapshotTest::SetUp();
userdata_ = std::make_unique<LowSpaceUserdata>();
@@ -1774,6 +1775,7 @@
}
void TearDown() override {
if (!is_virtual_ab_) return;
+ return; // BUG(149738928)
EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
image_manager_->DeleteBackingImage(kImageName));
@@ -1808,10 +1810,6 @@
std::vector<uint64_t> ret;
for (uint64_t size = 1_MiB; size <= 512_MiB; size *= 2) {
ret.push_back(size);
-#ifdef SKIP_TEST_IN_PRESUBMIT
- // BUG(148889015);
- break;
-#endif
}
return ret;
}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index e364436..cf324fe 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -902,7 +902,11 @@
done
# If reboot too soon after fresh flash, could trip device update failure logic
-wait_for_screen
+if ! wait_for_screen && ${screen_wait}; then
+ screen_wait=false
+ echo "${ORANGE}[ WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2
+fi
+
# Can we test remount -R command?
OVERLAYFS_BACKING="cache mnt/scratch"
overlayfs_supported=true
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 800ad7e..69b3150 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -895,11 +895,11 @@
EXPECT_EQ("/dir/key", entry->metadata_key_dir);
}
-TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataCipher) {
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults keydirectory=/dir/key,metadata_cipher=adiantum
+source none0 swap defaults keydirectory=/dir/key,metadata_encryption=adiantum
)fs";
ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
@@ -909,7 +909,28 @@
ASSERT_EQ(1U, fstab.size());
auto entry = fstab.begin();
- EXPECT_EQ("adiantum", entry->metadata_cipher);
+ EXPECT_EQ("adiantum", entry->metadata_encryption);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption_WrappedKey) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ std::string fstab_contents = R"fs(
+source none0 swap defaults keydirectory=/dir/key,metadata_encryption=aes-256-xts:wrappedkey_v0
+)fs";
+
+ ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+ Fstab fstab;
+ EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+ ASSERT_EQ(1U, fstab.size());
+
+ auto entry = fstab.begin();
+ EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption);
+ auto parts = android::base::Split(entry->metadata_encryption, ":");
+ EXPECT_EQ(2U, parts.size());
+ EXPECT_EQ("aes-256-xts", parts[0]);
+ EXPECT_EQ("wrappedkey_v0", parts[1]);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_SysfsPath) {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index b85f23f..8e9e074 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -55,6 +55,7 @@
using android::hardware::health::V1_0::BatteryHealth;
using android::hardware::health::V1_0::BatteryStatus;
using android::hardware::health::V2_1::BatteryCapacityLevel;
+using android::hardware::health::V2_1::Constants;
namespace android {
@@ -79,6 +80,8 @@
// HIDL enum values are zero initialized, so they need to be initialized
// properly.
health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
+ health_info_2_1->batteryChargeTimeToFullNowSeconds =
+ (int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
auto* props = &health_info_2_1->legacy.legacy;
props->batteryStatus = BatteryStatus::UNKNOWN;
props->batteryHealth = BatteryHealth::UNKNOWN;
@@ -134,13 +137,13 @@
{"Normal", BatteryCapacityLevel::NORMAL},
{"High", BatteryCapacityLevel::HIGH},
{"Full", BatteryCapacityLevel::FULL},
- {NULL, BatteryCapacityLevel::UNKNOWN},
+ {NULL, BatteryCapacityLevel::UNSUPPORTED},
};
auto ret = mapSysfsString(capacityLevel, batteryCapacityLevelMap);
if (!ret) {
- KLOG_WARNING(LOG_TAG, "Unknown battery capacity level '%s'\n", capacityLevel);
- *ret = BatteryCapacityLevel::UNKNOWN;
+ KLOG_WARNING(LOG_TAG, "Unsupported battery capacity level '%s'\n", capacityLevel);
+ *ret = BatteryCapacityLevel::UNSUPPORTED;
}
return *ret;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 38e8227..97d40b7 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -548,6 +548,7 @@
skip = strlen("reboot,");
}
SetProperty(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);
+ WriteStringToFile(reason.c_str() + skip, LAST_REBOOT_REASON_FILE);
sync();
bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
diff --git a/libcutils/include/cutils/android_reboot.h b/libcutils/include/cutils/android_reboot.h
index cd27eef..24e32d5 100644
--- a/libcutils/include/cutils/android_reboot.h
+++ b/libcutils/include/cutils/android_reboot.h
@@ -31,6 +31,7 @@
/* Android reboot reason stored in this property */
#define LAST_REBOOT_REASON_PROPERTY "persist.sys.boot.reason"
+#define LAST_REBOOT_REASON_FILE "/metadata/bootstat/" LAST_REBOOT_REASON_PROPERTY
/* Reboot or shutdown the system.
* This call uses ANDROID_RB_PROPERTY to request reboot to init process.
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index c84ddf7..c98455d 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -274,7 +274,7 @@
* Gets the minimum priority that will be logged for this process. If none has been set by a
* previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
*/
-int __android_log_get_minimum_priority();
+int __android_log_get_minimum_priority(void);
/**
* Sets the default tag if no tag is provided when writing a log message. Defaults to
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 0b38b6b..4aa439a 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -30,8 +30,7 @@
bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
- bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
#ifndef __ANDROID_VNDK__
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 6272664..d669ebe 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -115,9 +115,8 @@
TaskProfiles::GetInstance().DropResourceCaching();
}
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
- bool use_fd_cache) {
- return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, use_fd_cache);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+ return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles);
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 72f01af..4af4589 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -201,22 +201,6 @@
}
bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (IsFdValid()) {
- // fd is cached, reuse it
- if (!AddTidToCgroup(pid, fd_)) {
- LOG(ERROR) << "Failed to add task into cgroup";
- return false;
- }
- return true;
- }
-
- if (fd_ == FDS_INACCESSIBLE) {
- // no permissions to access the file, ignore
- return true;
- }
-
- // this is app-dependent path and fd is not cached or cached fd can't be used
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
@@ -270,7 +254,6 @@
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
- profile->EnableResourceCaching();
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "ExecuteForProcess failed for aggregate profile";
}
@@ -280,7 +263,6 @@
bool ApplyProfileAction::ExecuteForTask(int tid) const {
for (const auto& profile : profiles_) {
- profile->EnableResourceCaching();
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "ExecuteForTask failed for aggregate profile";
}
@@ -288,6 +270,18 @@
return true;
}
+void ApplyProfileAction::EnableResourceCaching() {
+ for (const auto& profile : profiles_) {
+ profile->EnableResourceCaching();
+ }
+}
+
+void ApplyProfileAction::DropResourceCaching() {
+ for (const auto& profile : profiles_) {
+ profile->DropResourceCaching();
+ }
+}
+
void TaskProfile::MoveTo(TaskProfile* profile) {
profile->elements_ = std::move(elements_);
profile->res_cached_ = res_cached_;
@@ -527,13 +521,10 @@
}
bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
- const std::vector<std::string>& profiles, bool use_fd_cache) {
+ const std::vector<std::string>& profiles) {
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
- if (use_fd_cache) {
- profile->EnableResourceCaching();
- }
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index a64ca50..28bc00c 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -163,6 +163,8 @@
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
+ virtual void EnableResourceCaching();
+ virtual void DropResourceCaching();
private:
std::vector<std::shared_ptr<TaskProfile>> profiles_;
@@ -176,8 +178,7 @@
TaskProfile* GetProfile(const std::string& name) const;
const ProfileAttribute* GetAttribute(const std::string& name) const;
void DropResourceCaching() const;
- bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
- bool use_fd_cache);
+ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
private:
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index ccda5d1..627f0d4 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -39,6 +39,10 @@
"clang-analyzer-security*",
"android-*",
],
+ apex_available: [
+ "//apex_available:anyapex",
+ "//apex_available:platform",
+ ],
}
cc_test {
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 08e3d22..76a970f 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1129,7 +1129,7 @@
if (!ret) {
error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
-This means that either logd crashed, or more likely, this instance of logcat was unable to read log
+This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
messages as quickly as they were being produced.
If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 782f967..91dd7a5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -386,6 +386,10 @@
# Start logd before any other services run to ensure we capture all of their logs.
start logd
# Start lmkd before any other services run so that it can register them
+ chown root system /sys/module/lowmemorykiller/parameters/adj
+ chmod 0664 /sys/module/lowmemorykiller/parameters/adj
+ chown root system /sys/module/lowmemorykiller/parameters/minfree
+ chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
start lmkd
# Start essential services.
@@ -496,6 +500,7 @@
mkdir /metadata/vold
chmod 0700 /metadata/vold
mkdir /metadata/password_slots 0771 root system
+ mkdir /metadata/bootstat 0750 system log
mkdir /metadata/ota 0700 root system
mkdir /metadata/ota/snapshots 0700 root system
@@ -824,10 +829,6 @@
# parameters to match how it is managing things.
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
- chown root system /sys/module/lowmemorykiller/parameters/adj
- chmod 0664 /sys/module/lowmemorykiller/parameters/adj
- chown root system /sys/module/lowmemorykiller/parameters/minfree
- chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
# System server manages zram writeback
chown root system /sys/block/zram0/idle