Simplify compos key handling

The new interface to the VM instance secrets already provides a
context-specific secret so it can be used directly as the seed for the
key without requiring another derivation.

Bug: 243514248
Test: atest ComposHostTestCases
Test: atest compos_key_tests
Change-Id: Ibbff27cc6e4e8f499bf70ff6ce171f6cd7765288
This commit is contained in:
Andrew Scull 2022-10-07 19:47:53 +00:00
parent b3dd8af067
commit 7c6e4185bb
4 changed files with 26 additions and 35 deletions

View File

@ -24,25 +24,11 @@ using android::base::ErrnoError;
using android::base::Error;
using android::base::Result;
using compos_key::Ed25519KeyPair;
using compos_key::Seed;
using compos_key::Signature;
// Used to ensure the key we derive is distinct from any other.
constexpr const char* kSigningKeyInfo = "CompOS signing key";
namespace compos_key {
Result<Ed25519KeyPair> deriveKeyFromSecret(const uint8_t* secret, size_t secret_size) {
// Ed25519 private keys are derived from a 32 byte seed:
// https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5
std::array<uint8_t, 32> seed;
// We derive the seed from the secret using HKDF - see
// https://datatracker.ietf.org/doc/html/rfc5869#section-2.
if (!HKDF(seed.data(), seed.size(), EVP_sha256(), secret, secret_size, /*salt=*/nullptr,
/*salt_len=*/0, reinterpret_cast<const uint8_t*>(kSigningKeyInfo),
strlen(kSigningKeyInfo))) {
return Error() << "HKDF failed";
}
Result<Ed25519KeyPair> keyFromSeed(const Seed& seed) {
Ed25519KeyPair result;
ED25519_keypair_from_seed(result.public_key.data(), result.private_key.data(), seed.data());
return result;

View File

@ -22,8 +22,11 @@
#include <array>
namespace compos_key {
constexpr size_t ED25519_SEED_LEN = 32;
using PrivateKey = std::array<uint8_t, ED25519_PRIVATE_KEY_LEN>;
using PublicKey = std::array<uint8_t, ED25519_PUBLIC_KEY_LEN>;
using Seed = std::array<uint8_t, ED25519_SEED_LEN>;
using Signature = std::array<uint8_t, ED25519_SIGNATURE_LEN>;
struct Ed25519KeyPair {
@ -31,8 +34,7 @@ struct Ed25519KeyPair {
PublicKey public_key;
};
android::base::Result<Ed25519KeyPair> deriveKeyFromSecret(const uint8_t* secret,
size_t secret_size);
android::base::Result<Ed25519KeyPair> keyFromSeed(const Seed& seed);
android::base::Result<Signature> sign(const PrivateKey& private_key, const uint8_t* data,
size_t data_size);

View File

@ -29,22 +29,23 @@ using android::base::Result;
using android::base::WriteFully;
using namespace std::literals;
using compos_key::Ed25519KeyPair;
using compos_key::Seed;
namespace {
constexpr const char* kSigningKeySecretIdentifier = "CompOS signing key secret";
constexpr const char* kSigningKeySeedIdentifier = "CompOS signing key seed";
Result<Ed25519KeyPair> deriveKeyFromDice() {
uint8_t secret[32];
if (!get_vm_instance_secret(kSigningKeySecretIdentifier, strlen(kSigningKeySecretIdentifier),
secret, sizeof(secret))) {
return Error() << "Failed to get signing key secret";
Result<Ed25519KeyPair> getSigningKey() {
Seed seed;
if (!get_vm_instance_secret(kSigningKeySeedIdentifier, strlen(kSigningKeySeedIdentifier),
seed.data(), seed.size())) {
return Error() << "Failed to get signing key seed";
}
return compos_key::deriveKeyFromSecret(secret, sizeof(secret));
return compos_key::keyFromSeed(seed);
}
int write_public_key() {
auto key_pair = deriveKeyFromDice();
auto key_pair = getSigningKey();
if (!key_pair.ok()) {
LOG(ERROR) << key_pair.error();
return 1;
@ -79,7 +80,7 @@ int sign_input() {
return 1;
}
auto key_pair = deriveKeyFromDice();
auto key_pair = getSigningKey();
if (!key_pair.ok()) {
LOG(ERROR) << key_pair.error();
return 1;

View File

@ -22,30 +22,32 @@
using namespace compos_key;
const std::vector<uint8_t> secret = {1, 2, 3};
const std::vector<uint8_t> other_secret = {3, 2, 3};
constexpr Seed seed = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
constexpr Seed other_seed = {3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2,
3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2};
const std::vector<uint8_t> data = {42, 180, 65, 0};
struct ComposKeyTest : public testing::Test {
Ed25519KeyPair key_pair;
void SetUp() override {
auto key_pair = deriveKeyFromSecret(secret.data(), secret.size());
auto key_pair = keyFromSeed(seed);
ASSERT_TRUE(key_pair.ok()) << key_pair.error();
this->key_pair = *key_pair;
}
};
TEST_F(ComposKeyTest, SameSecretSameKey) {
auto other_key_pair = deriveKeyFromSecret(secret.data(), secret.size());
TEST_F(ComposKeyTest, SameSeedSameKey) {
auto other_key_pair = keyFromSeed(seed);
ASSERT_TRUE(other_key_pair.ok()) << other_key_pair.error();
ASSERT_EQ(key_pair.private_key, other_key_pair->private_key);
ASSERT_EQ(key_pair.public_key, other_key_pair->public_key);
}
TEST_F(ComposKeyTest, DifferentSecretDifferentKey) {
auto other_key_pair = deriveKeyFromSecret(other_secret.data(), other_secret.size());
TEST_F(ComposKeyTest, DifferentSeedDifferentKey) {
auto other_key_pair = keyFromSeed(other_seed);
ASSERT_TRUE(other_key_pair.ok()) << other_key_pair.error();
ASSERT_NE(key_pair.private_key, other_key_pair->private_key);
@ -84,7 +86,7 @@ TEST_F(ComposKeyTest, WrongDataDoesNotVerify) {
TEST_F(ComposKeyTest, WrongKeyDoesNotVerify) {
auto signature = sign(key_pair.private_key, data.data(), data.size());
auto other_key_pair = deriveKeyFromSecret(other_secret.data(), other_secret.size());
auto other_key_pair = keyFromSeed(other_seed);
ASSERT_TRUE(other_key_pair.ok()) << other_key_pair.error();
bool verified = verify(other_key_pair->public_key, *signature, data.data(), data.size());