[adbwifi] Add tls_connection library.
Bug: 111434128, 119494503, 119493510
Test: atest adb_tls_connection_test
Exempt-From-Owner-Approval: yolo?
Change-Id: Ie9b629e4cb955702cec890bbb89a6a762e4b71b3
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..8d37bbe
--- /dev/null
+++ b/adb/tls/adb_ca_list.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 kAdbKeyIdentifierPrefix[] = "AdbKey-";
+static constexpr int kAdbKeyVersion = 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*
+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 {};
+ }
+
+ // 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 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 = kAdbKeyIdentifierPrefix;
+ identifier += std::to_string(kAdbKeyVersion);
+ 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 || !android::base::StartsWith(*buf, kAdbKeyIdentifierPrefix)) {
+ return {};
+ }
+
+ return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
+}
+
+std::string SHA256BitsToHexString(std::string_view sha256) {
+ CHECK_EQ(sha256.size(), static_cast<size_t>(SHA256_DIGEST_LENGTH));
+ std::stringstream ss;
+ ss << std::uppercase << std::setfill('0') << std::hex;
+ // Convert to hex-string representation
+ for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+ ss << std::setw(2) << (0x00FF & sha256[i]);
+ }
+ return ss.str();
+}
+
+std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str) {
+ if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) {
+ return {};
+ }
+
+ 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 {};
+ }
+ 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..ae70857
--- /dev/null
+++ b/adb/tls/include/adb/tls/tls_connection.h
@@ -0,0 +1,127 @@
+/*
+ * 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. Use
+ // |EnableCertificateVerification(false)| to disable certificate
+ // verification.
+ //
+ // 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. Note that |cb| is
+ // only used if EnableCertificateVerification(false).
+ 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..880904b
--- /dev/null
+++ b/adb/tls/tests/tls_connection_test.cpp
@@ -0,0 +1,616 @@
+/*
+ * 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 {
+ // TODO: move client code in each test into its own thread, as the
+ // socket pair buffer is limited.
+ 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(bool expect_success) {
+ client_thread_ = std::thread([=]() {
+ if (expect_success) {
+ EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+ } else {
+ EXPECT_NE(client_->DoHandshake(), TlsError::Success);
+ }
+ });
+ }
+
+ 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(true);
+
+ // Handshake should succeed
+ EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Client write, server read
+ EXPECT_TRUE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data, msg_);
+
+ // Client read, server write
+ EXPECT_TRUE(server_->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_);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, NoTrustedCertificates) {
+ StartClientHandshakeAsync(false);
+
+ // Handshake should not succeed
+ EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Client write, server read should fail
+ EXPECT_FALSE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+
+ // Client read, server write should fail
+ EXPECT_FALSE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates) {
+ // Add peer certificates
+ EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
+
+ StartClientHandshakeAsync(true);
+
+ // Handshake should succeed
+ EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Client write, server read
+ EXPECT_TRUE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data, msg_);
+
+ // Client read, server write
+ EXPECT_TRUE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data, msg_);
+}
+
+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(true);
+
+ // Handshake should fail for server, succeed for client
+ EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Client write succeeds, server read should fail
+ EXPECT_TRUE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+
+ // Client read, server write should fail
+ EXPECT_FALSE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+}
+
+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(true);
+
+ // Handshake should succeed
+ EXPECT_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.
+ client_thread_ = std::thread([&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::Success); });
+
+ // Server handshake should fail
+ EXPECT_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
+ client_thread_ = std::thread(
+ [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::PeerRejectedCertificate); });
+
+ // Server handshake should fail
+ EXPECT_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
+ client_thread_ = std::thread(
+ [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::CertificateRejected); });
+
+ // Server handshake should fail
+ EXPECT_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
+ client_thread_ = std::thread(
+ [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::CertificateRejected); });
+
+ // Server handshake should fail
+ EXPECT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+ WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, EnableClientPostHandshakeCheck_ClientWrongCert) {
+ // 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(false);
+
+ // Handshake should fail for server
+ EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+ WaitForClientConnection();
+
+ // Client write fails, server read should fail
+ EXPECT_FALSE(client_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ auto data = server_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+
+ // Client read, server write should fail
+ EXPECT_FALSE(server_->WriteFully(
+ std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+ data = client_->ReadFully(msg_.size());
+ EXPECT_EQ(data.size(), 0);
+}
+
+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
+ EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+ });
+
+ EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+ // Server handshake should succeed
+ EXPECT_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
+ EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+ });
+
+ server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+ // Server handshake should succeed
+ EXPECT_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..7df6ef4
--- /dev/null
+++ b/adb/tls/tls_connection.cpp
@@ -0,0 +1,387 @@
+/*
+ * 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);
+
+ 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_;
+}; // 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) << "Initializing adbwifi TlsConnection";
+ cert_ = BufferFromPEM(cert);
+ priv_key_ = EvpPkeyFromPEM(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) << "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() {
+ int err = -1;
+ LOG(INFO) << "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) << "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) << "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) << "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) << "SSL_set_fd failed. [" << SSLErrorString() << "]";
+ return TlsError::UnknownFailure;
+ }
+ switch (role_) {
+ case Role::Server:
+ err = SSL_accept(ssl_.get());
+ break;
+ case Role::Client:
+ err = SSL_connect(ssl_.get());
+ break;
+ }
+ if (err != 1) {
+ LOG(ERROR) << "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.
+ err = SSL_peek(ssl_.get(), &check, 1);
+ if (err <= 0) {
+ LOG(ERROR) << "Post-handshake SSL_peek failed [" << SSLErrorString() << "]";
+ auto sslerr = ERR_get_error();
+ Invalidate();
+ return GetFailureReason(sslerr);
+ }
+ }
+
+ LOG(INFO) << "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) << "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(WARNING) << "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) << "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(WARNING) << "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