Move adb RSA utilities into its own library.
Since both the client and daemon will now be generating keys. BUG: b/111434128 Test: atest adb_crypto_test Change-Id: I6fac562ae5629ab30b6639fbd88d822dae6e96bd
This commit is contained in:
parent
9e96e71067
commit
ef28ca4cdc
14 changed files with 717 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
|
||||
Loading…
Add table
Reference in a new issue