#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 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 client; static unique_ptr service; static unique_ptr 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 ImportKeyTest::client; unique_ptr ImportKeyTest::service; unique_ptr 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(); 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(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 x(BN_new()); bssl::UniquePtr 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 dstr(new uint8_t[field_size]); std::unique_ptr xstr(new uint8_t[field_size]); std::unique_ptr 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