Merge changes from topic "adbwifi-syscore-base"
* changes: [adbwifi] Add tls_connection library. Move adb RSA utilities into its own library. [adbwifi] Add adb protos.
This commit is contained in:
commit
fd8b4ea996
27 changed files with 2463 additions and 72 deletions
|
@ -3,6 +3,12 @@
|
|||
{
|
||||
"name": "adbd_test"
|
||||
},
|
||||
{
|
||||
"name": "adb_crypto_test"
|
||||
},
|
||||
{
|
||||
"name": "adb_tls_connection_test"
|
||||
},
|
||||
{
|
||||
"name": "CtsInitTestCases"
|
||||
},
|
||||
|
|
|
@ -255,6 +255,8 @@ cc_library_host_static {
|
|||
},
|
||||
|
||||
static_libs: [
|
||||
"libadb_crypto",
|
||||
"libadb_protos",
|
||||
"libbase",
|
||||
"libcrypto_utils",
|
||||
"libcrypto",
|
||||
|
@ -272,6 +274,7 @@ cc_test_host {
|
|||
defaults: ["adb_defaults"],
|
||||
srcs: libadb_test_srcs,
|
||||
static_libs: [
|
||||
"libadb_crypto",
|
||||
"libadb_host",
|
||||
"libbase",
|
||||
"libcutils",
|
||||
|
@ -347,6 +350,7 @@ cc_binary_host {
|
|||
],
|
||||
|
||||
static_libs: [
|
||||
"libadb_crypto",
|
||||
"libadb_host",
|
||||
"libandroidfw",
|
||||
"libbase",
|
||||
|
@ -422,6 +426,7 @@ cc_library_static {
|
|||
],
|
||||
|
||||
shared_libs: [
|
||||
"libadb_crypto",
|
||||
"libadbd_auth",
|
||||
"libasyncio",
|
||||
"libbase",
|
||||
|
@ -765,6 +770,7 @@ cc_test_host {
|
|||
"fastdeploy/deploypatchgenerator/patch_utils_test.cpp",
|
||||
],
|
||||
static_libs: [
|
||||
"libadb_crypto",
|
||||
"libadb_host",
|
||||
"libandroidfw",
|
||||
"libbase",
|
||||
|
|
|
@ -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 @@ static std::map<std::string, std::shared_ptr<RSA>>& g_keys =
|
|||
*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 @@ static bool pubkey_from_privkey(std::string* out, const std::string& path) {
|
|||
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 @@ std::string adb_auth_get_userkey() {
|
|||
}
|
||||
|
||||
int adb_auth_keygen(const char* filename) {
|
||||
return (generate_key(filename) == 0);
|
||||
return !generate_key(filename);
|
||||
}
|
||||
|
||||
int adb_auth_pubkey(const char* filename) {
|
||||
|
|
85
adb/crypto/Android.bp
Normal file
85
adb/crypto/Android.bp
Normal file
|
@ -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",
|
||||
],
|
||||
}
|
46
adb/crypto/include/adb/crypto/key.h
Normal file
46
adb/crypto/include/adb/crypto/key.h
Normal file
|
@ -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
|
34
adb/crypto/include/adb/crypto/rsa_2048_key.h
Normal file
34
adb/crypto/include/adb/crypto/rsa_2048_key.h
Normal file
|
@ -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
|
31
adb/crypto/include/adb/crypto/x509_generator.h
Normal file
31
adb/crypto/include/adb/crypto/x509_generator.h
Normal file
|
@ -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
|
47
adb/crypto/key.cpp
Normal file
47
adb/crypto/key.cpp
Normal file
|
@ -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
|
87
adb/crypto/rsa_2048_key.cpp
Normal file
87
adb/crypto/rsa_2048_key.cpp
Normal file
|
@ -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
|
41
adb/crypto/tests/Android.bp
Normal file
41
adb/crypto/tests/Android.bp
Normal file
|
@ -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"],
|
||||
}
|
70
adb/crypto/tests/key_test.cpp
Normal file
70
adb/crypto/tests/key_test.cpp
Normal file
|
@ -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
|
73
adb/crypto/tests/rsa_2048_key_test.cpp
Normal file
73
adb/crypto/tests/rsa_2048_key_test.cpp
Normal file
|
@ -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
|
45
adb/crypto/tests/x509_generator_test.cpp
Normal file
45
adb/crypto/tests/x509_generator_test.cpp
Normal file
|
@ -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
|
123
adb/crypto/x509_generator.cpp
Normal file
123
adb/crypto/x509_generator.cpp
Normal file
|
@ -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
|
70
adb/proto/Android.bp
Normal file
70
adb/proto/Android.bp
Normal file
|
@ -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",
|
||||
],
|
||||
}
|
32
adb/proto/adb_known_hosts.proto
Normal file
32
adb/proto/adb_known_hosts.proto
Normal file
|
@ -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;
|
||||
}
|
1
adb/proto/jarjar-rules.txt
Normal file
1
adb/proto/jarjar-rules.txt
Normal file
|
@ -0,0 +1 @@
|
|||
rule com.google.protobuf.** com.android.framework.protobuf.@1
|
26
adb/proto/key_type.proto
Normal file
26
adb/proto/key_type.proto
Normal file
|
@ -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;
|
||||
}
|
30
adb/proto/pairing.proto
Normal file
30
adb/proto/pairing.proto
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
75
adb/tls/Android.bp
Normal file
75
adb/tls/Android.bp
Normal file
|
@ -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",
|
||||
],
|
||||
}
|
130
adb/tls/adb_ca_list.cpp
Normal file
130
adb/tls/adb_ca_list.cpp
Normal file
|
@ -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
|
47
adb/tls/include/adb/tls/adb_ca_list.h
Normal file
47
adb/tls/include/adb/tls/adb_ca_list.h
Normal file
|
@ -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
|
127
adb/tls/include/adb/tls/tls_connection.h
Normal file
127
adb/tls/include/adb/tls/tls_connection.h
Normal file
|
@ -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
|
42
adb/tls/tests/Android.bp
Normal file
42
adb/tls/tests/Android.bp
Normal file
|
@ -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"],
|
||||
}
|
163
adb/tls/tests/adb_ca_list_test.cpp
Normal file
163
adb/tls/tests/adb_ca_list_test.cpp
Normal file
|
@ -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
|
616
adb/tls/tests/tls_connection_test.cpp
Normal file
616
adb/tls/tests/tls_connection_test.cpp
Normal file
|
@ -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
|
387
adb/tls/tls_connection.cpp
Normal file
387
adb/tls/tls_connection.cpp
Normal file
|
@ -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
|
Loading…
Reference in a new issue