blob: 464432b08b421d154f9aacfca069157db445d44e [file] [log] [blame]
// Copyright 2019 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android-qemu2-glue/android_pubkey.h"
#include "android/utils/debug.h"
#include "android/utils/file_io.h"
#include <openssl/base64.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <string>
#include <vector>
// Size of an RSA modulus such as an encrypted block or a signature.
#define ANDROID_PUBKEY_MODULUS_SIZE (2048 / 8)
// Size of an encoded RSA key.
#define ANDROID_PUBKEY_ENCODED_SIZE \
(3 * sizeof(uint32_t) + 2 * ANDROID_PUBKEY_MODULUS_SIZE)
// From ${AOSP}/system/core/adb/client/auth.cpp
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))) {
fprintf(stderr, "Failed to convert to public key\n");
return false;
}
size_t expected_length;
if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) {
fprintf(stderr, "Public key too large to base64 encode\n");
return false;
}
std::vector<char> buffer(expected_length);
size_t actual_length =
EVP_EncodeBlock(reinterpret_cast<uint8_t*>(buffer.data()),
binary_key_data, sizeof(binary_key_data));
out->assign(buffer.data(), actual_length);
return true;
}
static std::shared_ptr<RSA> read_key_file(const std::string& file) {
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"),
fclose);
if (!fp) {
fprintf(stderr, "Failed to open '%s'\n", file.c_str());
return nullptr;
}
RSA* key = RSA_new();
if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
fprintf(stderr, "Failed to read key\n");
RSA_free(key);
return nullptr;
}
return std::shared_ptr<RSA>(key, RSA_free);
}
static bool generate_key(const std::string& file) {
VERBOSE_PRINT(init, "generate_key(%s)...", file.c_str());
mode_t old_mask;
FILE* f = nullptr;
bool ret = 0;
EVP_PKEY* pkey = EVP_PKEY_new();
BIGNUM* exponent = BN_new();
RSA* rsa = RSA_new();
if (!pkey || !exponent || !rsa) {
dwarning("Failed to allocate key");
goto out;
}
BN_set_word(exponent, RSA_F4);
RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
EVP_PKEY_set1_RSA(pkey, rsa);
f = fopen(file.c_str(), "w");
if (!f) {
dwarning("Failed to open %s", file.c_str());
goto out;
}
if (!PEM_write_PrivateKey(f, pkey, nullptr, nullptr, 0, nullptr, nullptr)) {
dwarning("Failed to write key");
goto out;
}
fclose(f);
f = NULL;
android_chmod(file.c_str(), 0777);
ret = true;
out:
if (f) {
fclose(f);
}
EVP_PKEY_free(pkey);
RSA_free(rsa);
BN_free(exponent);
return ret;
}
bool adb_auth_keygen(const char* filename) {
return generate_key(filename);
}
bool pubkey_from_privkey(const std::string& path, std::string* out) {
std::shared_ptr<RSA> privkey = read_key_file(path);
if (!privkey) {
return false;
}
return calculate_public_key(out, privkey.get());
}