blob: 4e2e531bbd877973ad1d00c99bee77bf1afaed44 [file] [log] [blame]
#include "gtest/gtest.h"
#include "avb_tools.h"
#include "keymaster_tools.h"
#include "nugget_tools.h"
#include "nugget/app/keymaster/keymaster.pb.h"
#include "nugget/app/keymaster/keymaster_defs.pb.h"
#include "nugget/app/keymaster/keymaster_types.pb.h"
#include "Keymaster.client.h"
#include "util.h"
#include "src/macros.h"
#include "src/test-data/test-keys/rsa.h"
#include "openssl/bn.h"
#include "openssl/ec_key.h"
#include "openssl/nid.h"
#include <sstream>
using std::cout;
using std::string;
using std::stringstream;
using std::unique_ptr;
using namespace nugget::app::keymaster;
using namespace test_data;
namespace {
class ImportKeyTest: public testing::Test {
protected:
static unique_ptr<nos::NuggetClientInterface> client;
static unique_ptr<Keymaster> service;
static unique_ptr<test_harness::TestHarness> uart_printer;
static void SetUpTestCase();
static void TearDownTestCase();
void initRSARequest(ImportKeyRequest *request, Algorithm alg) {
KeyParameters *params = request->mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)alg);
}
void initRSARequest(ImportKeyRequest *request, Algorithm alg, int key_size) {
initRSARequest(request, alg);
if (key_size >= 0) {
KeyParameters *params = request->mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::KEY_SIZE);
param->set_integer(key_size);
}
}
void initRSARequest(ImportKeyRequest *request, Algorithm alg, int key_size,
int public_exponent_tag) {
initRSARequest(request, alg, key_size);
if (public_exponent_tag >= 0) {
KeyParameters *params = request->mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::RSA_PUBLIC_EXPONENT);
param->set_long_integer(public_exponent_tag);
}
}
void initRSARequest(ImportKeyRequest *request, Algorithm alg, int key_size,
int public_exponent_tag, uint32_t public_exponent,
const string& d, const string& n) {
initRSARequest(request, alg, key_size, public_exponent_tag);
request->mutable_rsa()->set_e(public_exponent);
request->mutable_rsa()->set_d(d);
request->mutable_rsa()->set_n(n);
}
};
unique_ptr<nos::NuggetClientInterface> ImportKeyTest::client;
unique_ptr<Keymaster> ImportKeyTest::service;
unique_ptr<test_harness::TestHarness> ImportKeyTest::uart_printer;
void ImportKeyTest::SetUpTestCase() {
uart_printer = test_harness::TestHarness::MakeUnique();
client = nugget_tools::MakeNuggetClient();
client->Open();
EXPECT_TRUE(client->IsOpen()) << "Unable to connect";
service.reset(new Keymaster(*client));
// Do setup that is normally done by the bootloader.
keymaster_tools::SetRootOfTrust(client.get());
keymaster_tools::SetBootState(client.get());
}
void ImportKeyTest::TearDownTestCase() {
client->Close();
client = unique_ptr<nos::NuggetClientInterface>();
uart_printer = nullptr;
}
// TODO: refactor into import key tests.
// Failure cases.
TEST_F(ImportKeyTest, AlgorithmMissingFails) {
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
/* Algorithm tag is unspecified, import should fail. */
KeyParameter *param = params->add_params();
param->set_tag(Tag::KEY_SIZE);
param->set_integer(512);
param = params->add_params();
param->set_tag(Tag::RSA_PUBLIC_EXPONENT);
param->set_long_integer(3);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
// RSA
TEST_F(ImportKeyTest, RSAInvalidKeySizeFails) {
ImportKeyRequest request;
ImportKeyResponse response;
initRSARequest(&request, Algorithm::RSA, 256, 3);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::UNSUPPORTED_KEY_SIZE);
}
TEST_F(ImportKeyTest, RSAInvalidPublicExponentFails) {
ImportKeyRequest request;
ImportKeyResponse response;
// Unsupported exponent
initRSARequest(&request, Algorithm::RSA, 1024, 2, 2,
string(64, '\0'), string(64, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
ErrorCode::UNSUPPORTED_KEY_SIZE);
}
TEST_F(ImportKeyTest, RSAKeySizeTagMisatchNFails) {
ImportKeyRequest request;
ImportKeyResponse response;
// N does not match KEY_SIZE.
initRSARequest(&request, Algorithm::RSA, 1024, 3, 3,
string(64, '\0'), string(63, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
ErrorCode::IMPORT_PARAMETER_MISMATCH);
}
TEST_F(ImportKeyTest, RSAKeySizeTagMisatchDFails) {
ImportKeyRequest request;
ImportKeyResponse response;
// D does not match KEY_SIZE.
initRSARequest(&request, Algorithm::RSA, 1024, 3, 3,
string(63, '\0'), string(64, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
ErrorCode::IMPORT_PARAMETER_MISMATCH);
}
TEST_F(ImportKeyTest, RSAPublicExponentTagMisatchFails) {
ImportKeyRequest request;
ImportKeyResponse response;
// e does not match PUBLIC_EXPONENT tag.
initRSARequest(&request, Algorithm::RSA, 1024, 3, 2,
string(64, '\0'), string(64, '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(),
ErrorCode::IMPORT_PARAMETER_MISMATCH);
}
TEST_F(ImportKeyTest, RSA1024BadEFails) {
ImportKeyRequest request;
ImportKeyResponse response;
// Mis-matched e.
const string d((const char *)RSA_1024_D, sizeof(RSA_1024_D));
const string N((const char *)RSA_1024_N, sizeof(RSA_1024_N));
initRSARequest(&request, Algorithm::RSA, 1024, 3, 3, d, N);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F(ImportKeyTest, RSA1024BadDFails) {
ImportKeyRequest request;
ImportKeyResponse response;
const string d(string("\x01") + /* Twiddle LSB of D. */
string((const char *)RSA_1024_D, sizeof(RSA_1024_D) - 1));
const string N((const char *)RSA_1024_N, sizeof(RSA_1024_N));
initRSARequest(&request, Algorithm::RSA, 1024, 65537, 65537, d, N);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F(ImportKeyTest, RSA1024BadNFails) {
ImportKeyRequest request;
ImportKeyResponse response;
const string d((const char *)RSA_1024_D, sizeof(RSA_1024_D));
const string N(string("\x01") + /* Twiddle LSB of N. */
string((const char *)RSA_1024_N, sizeof(RSA_1024_N) - 1));
initRSARequest(&request, Algorithm::RSA, 1024, 65537, 65537, d, N);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F(ImportKeyTest, RSASuccess) {
ImportKeyRequest request;
ImportKeyResponse response;
initRSARequest(&request, Algorithm::RSA);
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
for (size_t i = 0; i < ARRAYSIZE(TEST_RSA_KEYS); i++) {
param->set_tag(Tag::RSA_PUBLIC_EXPONENT);
param->set_long_integer(TEST_RSA_KEYS[i].e);
request.mutable_rsa()->set_e(TEST_RSA_KEYS[i].e);
request.mutable_rsa()->set_d(TEST_RSA_KEYS[i].d, TEST_RSA_KEYS[i].size);
request.mutable_rsa()->set_n(TEST_RSA_KEYS[i].n, TEST_RSA_KEYS[i].size);
stringstream ss;
ss << "Failed at TEST_RSA_KEYS[" << i << "]";
ASSERT_NO_ERROR(service->ImportKey(request, &response), ss.str());
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK)
<< "Failed at TEST_RSA_KEYS[" << i << "]";
/* TODO: do something useful with the imported key */
}
}
TEST_F(ImportKeyTest, UpgradeSuccess) {
ImportKeyRequest request;
ImportKeyResponse response;
initRSARequest(&request, Algorithm::RSA);
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::RSA_PUBLIC_EXPONENT);
param->set_long_integer(TEST_RSA_KEYS[0].e);
request.mutable_rsa()->set_e(TEST_RSA_KEYS[0].e);
request.mutable_rsa()->set_d(TEST_RSA_KEYS[0].d, TEST_RSA_KEYS[0].size);
request.mutable_rsa()->set_n(TEST_RSA_KEYS[0].n, TEST_RSA_KEYS[0].size);
{
EXPECT_TRUE(nugget_tools::RebootNugget(client.get()))
<< "Failed to reboot nugget";
SetSystemVersionInfoRequest svRequest;
SetSystemVersionInfoResponse svResponse;
svRequest.set_system_version(1);
svRequest.set_system_security_level(1);
svRequest.set_vendor_security_level(1);
ASSERT_NO_ERROR(service->SetSystemVersionInfo(svRequest, &svResponse), "");
EXPECT_EQ((ErrorCode)svResponse.error_code(), ErrorCode::OK);
// Do setup that is normally done by the bootloader.
keymaster_tools::SetRootOfTrust(client.get());
keymaster_tools::SetBootState(client.get());
}
stringstream ss;
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK)
<< "Failed at TEST_RSA_KEYS[" << 0 << "]";
{
EXPECT_TRUE(nugget_tools::RebootNugget(client.get()))
<< "Failed to reboot nugget";
SetSystemVersionInfoRequest svRequest;
SetSystemVersionInfoResponse svResponse;
/* Bump vendor version level, to force Upgrade. */
svRequest.set_system_version(1);
svRequest.set_system_security_level(1);
svRequest.set_vendor_security_level(2);
ASSERT_NO_ERROR(service->SetSystemVersionInfo(svRequest, &svResponse), "");
EXPECT_EQ((ErrorCode)svResponse.error_code(), ErrorCode::OK);
// Do setup that is normally done by the bootloader.
keymaster_tools::SetRootOfTrust(client.get());
keymaster_tools::SetBootState(client.get());
}
{
GetKeyCharacteristicsRequest gkRequest;
GetKeyCharacteristicsResponse gkResponse;
gkRequest.mutable_blob()->set_blob(response.blob().blob().data(),
response.blob().blob().size());
ASSERT_NO_ERROR(service->GetKeyCharacteristics(gkRequest, &gkResponse), "");
EXPECT_EQ((ErrorCode)gkResponse.error_code(),
ErrorCode::KEY_REQUIRES_UPGRADE);
}
{
UpgradeKeyRequest ukRequest;
UpgradeKeyResponse ukResponse;
ukRequest.mutable_blob()->set_blob(response.blob().blob().data(),
response.blob().blob().size());
ASSERT_NO_ERROR(service->UpgradeKey(ukRequest, &ukResponse), "");
EXPECT_EQ((ErrorCode)ukResponse.error_code(), ErrorCode::OK);
// GetKeyCharacteristics succeeds after the UpgradeKey().
GetKeyCharacteristicsRequest gkRequest;
GetKeyCharacteristicsResponse gkResponse;
gkRequest.mutable_blob()->set_blob(ukResponse.blob().blob().data(),
ukResponse.blob().blob().size());
ASSERT_NO_ERROR(service->GetKeyCharacteristics(gkRequest, &gkResponse), "");
EXPECT_EQ((ErrorCode)gkResponse.error_code(), ErrorCode::OK);
}
}
TEST_F(ImportKeyTest, RSA1024OptionalParamsAbsentSuccess) {
ImportKeyRequest request;
ImportKeyResponse response;
initRSARequest(&request, Algorithm::RSA, -1, -1, 65537,
string((const char *)RSA_1024_D, sizeof(RSA_1024_D)),
string((const char *)RSA_1024_N, sizeof(RSA_1024_N)));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
/* TODO: do something useful with the imported key */
}
// EC
TEST_F(ImportKeyTest, ECMissingCurveIdTagFails) {
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::EC);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F(ImportKeyTest, ECMisMatchedCurveIdTagFails) {
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::EC);
param = params->add_params();
param->set_tag(Tag::EC_CURVE);
param->set_integer((uint32_t)EcCurve::P_256);
request.mutable_ec()->set_curve_id(((uint32_t)EcCurve::P_256) + 1);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F(ImportKeyTest, ECMisMatchedKeySizeTagCurveTagFails) {
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::EC);
param = params->add_params();
param->set_tag(Tag::EC_CURVE);
param->set_integer((uint32_t)EcCurve::P_256);
param = params->add_params();
param->set_tag(Tag::KEY_SIZE);
param->set_integer((uint32_t)384); /* Should be 256 */
request.mutable_ec()->set_curve_id((uint32_t)EcCurve::P_256);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F(ImportKeyTest, ECMisMatchedP256KeySizeFails) {
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::EC);
param = params->add_params();
param->set_tag(Tag::EC_CURVE);
param->set_integer((uint32_t)EcCurve::P_256);
request.mutable_ec()->set_curve_id((uint32_t)EcCurve::P_256);
request.mutable_ec()->set_d(string((256 >> 3) - 1, '\0'));
request.mutable_ec()->set_x(string((256 >> 3), '\0'));
request.mutable_ec()->set_y(string((256 >> 3), '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
// TODO: bad key tests. invalid d, {x,y} not on curve, d, xy mismatched.
TEST_F(ImportKeyTest, ECP256BadKeyFails) {
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::EC);
param = params->add_params();
param->set_tag(Tag::EC_CURVE);
param->set_integer((uint32_t)EcCurve::P_256);
request.mutable_ec()->set_curve_id((uint32_t)EcCurve::P_256);
request.mutable_ec()->set_d(string((256 >> 3), '\0'));
request.mutable_ec()->set_x(string((256 >> 3), '\0'));
request.mutable_ec()->set_y(string((256 >> 3), '\0'));
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::INVALID_ARGUMENT);
}
TEST_F (ImportKeyTest, ImportECP256KeySuccess) {
// Generate an EC key.
// TODO: just hardcode a test key.
bssl::UniquePtr<EC_KEY> ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
EXPECT_EQ(EC_KEY_generate_key(ec.get()), 1);
const EC_GROUP *group = EC_KEY_get0_group(ec.get());
const BIGNUM *d = EC_KEY_get0_private_key(ec.get());
const EC_POINT *point = EC_KEY_get0_public_key(ec.get());
bssl::UniquePtr<BIGNUM> x(BN_new());
bssl::UniquePtr<BIGNUM> y(BN_new());
EXPECT_EQ(EC_POINT_get_affine_coordinates_GFp(
group, point, x.get(), y.get(), NULL), 1);
// Turn d, x, y into binary strings.
const size_t field_size = (EC_GROUP_get_degree(group) + 7) >> 3;
std::unique_ptr<uint8_t []> dstr(new uint8_t[field_size]);
std::unique_ptr<uint8_t []> xstr(new uint8_t[field_size]);
std::unique_ptr<uint8_t []> ystr(new uint8_t[field_size]);
EXPECT_EQ(BN_bn2le_padded(dstr.get(), field_size, d), 1);
EXPECT_EQ(BN_bn2le_padded(xstr.get(), field_size, x.get()), 1);
EXPECT_EQ(BN_bn2le_padded(ystr.get(), field_size, y.get()), 1);
ImportKeyRequest request;
ImportKeyResponse response;
KeyParameters *params = request.mutable_params();
KeyParameter *param = params->add_params();
param->set_tag(Tag::ALGORITHM);
param->set_integer((uint32_t)Algorithm::EC);
param = params->add_params();
param->set_tag(Tag::EC_CURVE);
param->set_integer((uint32_t)EcCurve::P_256);
param = params->add_params();
param->set_tag(Tag::KEY_SIZE);
param->set_integer((uint32_t)256);
request.mutable_ec()->set_curve_id((uint32_t)EcCurve::P_256);
request.mutable_ec()->set_d(dstr.get(), field_size);
request.mutable_ec()->set_x(xstr.get(), field_size);
request.mutable_ec()->set_y(ystr.get(), field_size);
ASSERT_NO_ERROR(service->ImportKey(request, &response), "");
EXPECT_EQ((ErrorCode)response.error_code(), ErrorCode::OK);
}
// TODO: add tests for symmetric key import.
} // namespace