Merge "Add sanity check when loading public keys for OTA package"
am: 6793f61795
Change-Id: I28ee367d213c619bebce0c5e138aa426c41b92df
This commit is contained in:
commit
accb42d1b3
3 changed files with 84 additions and 6 deletions
|
@ -30,6 +30,9 @@
|
|||
#include <android-base/test_utils.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/nid.h>
|
||||
#include <ziparchive/zip_writer.h>
|
||||
|
||||
#include "common/test_constants.h"
|
||||
|
@ -148,6 +151,35 @@ TEST(VerifierTest, LoadCertificateFromBuffer_sha256_ec256bits) {
|
|||
VerifyPackageWithSingleCertificate("otasigned_v5.zip", std::move(cert));
|
||||
}
|
||||
|
||||
TEST(VerifierTest, LoadCertificateFromBuffer_check_rsa_keys) {
|
||||
std::unique_ptr<RSA, RSADeleter> rsa(RSA_new());
|
||||
std::unique_ptr<BIGNUM, decltype(&BN_free)> exponent(BN_new(), BN_free);
|
||||
BN_set_word(exponent.get(), 3);
|
||||
RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr);
|
||||
ASSERT_TRUE(CheckRSAKey(rsa));
|
||||
|
||||
// Exponent is expected to be 3 or 65537
|
||||
BN_set_word(exponent.get(), 17);
|
||||
RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr);
|
||||
ASSERT_FALSE(CheckRSAKey(rsa));
|
||||
|
||||
// Modulus is expected to be 2048.
|
||||
BN_set_word(exponent.get(), 3);
|
||||
RSA_generate_key_ex(rsa.get(), 1024, exponent.get(), nullptr);
|
||||
ASSERT_FALSE(CheckRSAKey(rsa));
|
||||
}
|
||||
|
||||
TEST(VerifierTest, LoadCertificateFromBuffer_check_ec_keys) {
|
||||
std::unique_ptr<EC_KEY, ECKEYDeleter> ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
ASSERT_EQ(1, EC_KEY_generate_key(ec.get()));
|
||||
ASSERT_TRUE(CheckECKey(ec));
|
||||
|
||||
// Expects 256-bit EC key with curve NIST P-256
|
||||
ec.reset(EC_KEY_new_by_curve_name(NID_secp224r1));
|
||||
ASSERT_EQ(1, EC_KEY_generate_key(ec.get()));
|
||||
ASSERT_FALSE(CheckECKey(ec));
|
||||
}
|
||||
|
||||
TEST(VerifierTest, LoadKeysFromZipfile_empty_archive) {
|
||||
TemporaryFile otacerts;
|
||||
BuildCertificateArchive({}, otacerts.release());
|
||||
|
|
52
verifier.cpp
52
verifier.cpp
|
@ -500,6 +500,48 @@ std::vector<Certificate> LoadKeysFromZipfile(const std::string& zip_name) {
|
|||
return result;
|
||||
}
|
||||
|
||||
bool CheckRSAKey(const std::unique_ptr<RSA, RSADeleter>& rsa) {
|
||||
if (!rsa) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const BIGNUM* out_n;
|
||||
const BIGNUM* out_e;
|
||||
RSA_get0_key(rsa.get(), &out_n, &out_e, nullptr /* private exponent */);
|
||||
auto modulus_bits = BN_num_bits(out_n);
|
||||
if (modulus_bits != 2048) {
|
||||
LOG(ERROR) << "Modulus should be 2048 bits long, actual: " << modulus_bits;
|
||||
return false;
|
||||
}
|
||||
|
||||
BN_ULONG exponent = BN_get_word(out_e);
|
||||
if (exponent != 3 && exponent != 65537) {
|
||||
LOG(ERROR) << "Public exponent should be 3 or 65537, actual: " << exponent;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckECKey(const std::unique_ptr<EC_KEY, ECKEYDeleter>& ec_key) {
|
||||
if (!ec_key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key.get());
|
||||
if (!ec_group) {
|
||||
LOG(ERROR) << "Failed to get the ec_group from the ec_key";
|
||||
return false;
|
||||
}
|
||||
auto degree = EC_GROUP_get_degree(ec_group);
|
||||
if (degree != 256) {
|
||||
LOG(ERROR) << "Field size of the ec key should be 256 bits long, actual: " << degree;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadCertificateFromBuffer(const std::vector<uint8_t>& pem_content, Certificate* cert) {
|
||||
std::unique_ptr<BIO, decltype(&BIO_free)> content(
|
||||
BIO_new_mem_buf(pem_content.data(), pem_content.size()), BIO_free);
|
||||
|
@ -538,22 +580,20 @@ bool LoadCertificateFromBuffer(const std::vector<uint8_t>& pem_content, Certific
|
|||
}
|
||||
|
||||
int key_type = EVP_PKEY_id(public_key.get());
|
||||
// TODO(xunchang) check the rsa key has exponent 3 or 65537 with RSA_get0_key; and ec key is
|
||||
// 256 bits.
|
||||
if (key_type == EVP_PKEY_RSA) {
|
||||
cert->key_type = Certificate::KEY_TYPE_RSA;
|
||||
cert->ec.reset();
|
||||
cert->rsa.reset(EVP_PKEY_get1_RSA(public_key.get()));
|
||||
if (!cert->rsa) {
|
||||
LOG(ERROR) << "Failed to get the rsa key info from public key";
|
||||
if (!cert->rsa || !CheckRSAKey(cert->rsa)) {
|
||||
LOG(ERROR) << "Failed to validate the rsa key info from public key";
|
||||
return false;
|
||||
}
|
||||
} else if (key_type == EVP_PKEY_EC) {
|
||||
cert->key_type = Certificate::KEY_TYPE_EC;
|
||||
cert->rsa.reset();
|
||||
cert->ec.reset(EVP_PKEY_get1_EC_KEY(public_key.get()));
|
||||
if (!cert->ec) {
|
||||
LOG(ERROR) << "Failed to get the ec key info from the public key";
|
||||
if (!cert->ec || !CheckECKey(cert->ec)) {
|
||||
LOG(ERROR) << "Failed to validate the ec key info from the public key";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -72,6 +72,12 @@ int verify_file(const unsigned char* addr, size_t length, const std::vector<Cert
|
|||
|
||||
bool load_keys(const char* filename, std::vector<Certificate>& certs);
|
||||
|
||||
// Checks that the RSA key has a modulus of 2048 bits long, and public exponent is 3 or 65537.
|
||||
bool CheckRSAKey(const std::unique_ptr<RSA, RSADeleter>& rsa);
|
||||
|
||||
// Checks that the field size of the curve for the EC key is 256 bits.
|
||||
bool CheckECKey(const std::unique_ptr<EC_KEY, ECKEYDeleter>& ec_key);
|
||||
|
||||
// Parses a PEM-encoded x509 certificate from the given buffer and saves it into |cert|. Returns
|
||||
// false if there is a parsing failure or the signature's encryption algorithm is not supported.
|
||||
bool LoadCertificateFromBuffer(const std::vector<uint8_t>& pem_content, Certificate* cert);
|
||||
|
|
Loading…
Reference in a new issue