blob: 689cb85ab3b3bada0e06121dd1eb1a76dd59fe00 [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "arc/keymaster/context/chaps_client.h"
#include <cstdint>
#include <vector>
#include <brillo/secure_blob.h>
#include <chaps/attributes.h>
#include <chaps/chaps_proxy_mock.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "arc/keymaster/context/context_adaptor.h"
#include "chaps/pkcs11/pkcs11t.h"
using ::testing::_;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace arc {
namespace keymaster {
namespace context {
namespace {
// Arbitrary non-zero CK_SESSION_HANDLE.
constexpr uint64_t kSessionId = 9;
// Arbitrary single-element list.
const std::vector<uint64_t> kObjectList = {7};
const std::vector<uint64_t> kEmptyObjectList = {};
// Arbitrary 32 byte key.
const std::vector<uint8_t> kKeyBlob(32, 99);
// Arbitrary blob containing a valid certificate x509 in DER format.
const std::vector<uint8_t> kCertificateDer = {
48, 130, 3, 107, 48, 130, 2, 83, 160, 3, 2, 1, 2, 2, 20,
105, 145, 5, 180, 104, 132, 151, 128, 121, 135, 72, 134, 120, 62, 120,
253, 190, 80, 104, 131, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13,
1, 1, 11, 5, 0, 48, 69, 49, 11, 48, 9, 6, 3, 85, 4,
6, 19, 2, 65, 85, 49, 19, 48, 17, 6, 3, 85, 4, 8, 12,
10, 83, 111, 109, 101, 45, 83, 116, 97, 116, 101, 49, 33, 48, 31,
6, 3, 85, 4, 10, 12, 24, 73, 110, 116, 101, 114, 110, 101, 116,
32, 87, 105, 100, 103, 105, 116, 115, 32, 80, 116, 121, 32, 76, 116,
100, 48, 30, 23, 13, 50, 48, 49, 50, 48, 51, 49, 48, 53, 49,
48, 49, 90, 23, 13, 50, 49, 49, 50, 48, 51, 49, 48, 53, 49,
48, 49, 90, 48, 69, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19,
2, 65, 85, 49, 19, 48, 17, 6, 3, 85, 4, 8, 12, 10, 83,
111, 109, 101, 45, 83, 116, 97, 116, 101, 49, 33, 48, 31, 6, 3,
85, 4, 10, 12, 24, 73, 110, 116, 101, 114, 110, 101, 116, 32, 87,
105, 100, 103, 105, 116, 115, 32, 80, 116, 121, 32, 76, 116, 100, 48,
130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1,
1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1,
1, 0, 175, 103, 224, 10, 106, 96, 140, 64, 134, 186, 210, 5, 92,
160, 224, 117, 88, 148, 184, 148, 135, 242, 95, 65, 112, 75, 77, 80,
68, 216, 98, 95, 39, 219, 229, 176, 19, 25, 149, 142, 151, 1, 221,
192, 6, 7, 201, 133, 186, 45, 237, 28, 210, 126, 136, 190, 68, 242,
232, 131, 168, 236, 18, 236, 236, 163, 33, 130, 235, 131, 210, 49, 236,
108, 245, 182, 26, 249, 109, 223, 158, 33, 187, 222, 89, 151, 134, 213,
46, 198, 215, 57, 239, 143, 132, 108, 69, 106, 97, 158, 144, 13, 112,
226, 137, 186, 234, 91, 48, 97, 253, 248, 245, 123, 101, 183, 137, 183,
39, 115, 26, 19, 201, 248, 71, 210, 172, 110, 98, 136, 224, 103, 222,
212, 156, 219, 69, 50, 18, 85, 180, 83, 84, 209, 176, 62, 94, 166,
91, 99, 78, 59, 36, 23, 23, 152, 215, 145, 248, 5, 253, 240, 29,
42, 125, 130, 109, 243, 10, 175, 149, 169, 102, 61, 106, 63, 156, 17,
185, 134, 199, 84, 7, 99, 231, 161, 222, 146, 161, 16, 27, 247, 178,
137, 57, 111, 252, 132, 113, 190, 46, 75, 107, 243, 125, 1, 153, 133,
86, 88, 141, 187, 27, 13, 53, 74, 156, 169, 87, 82, 192, 169, 44,
101, 3, 145, 251, 83, 171, 123, 188, 141, 137, 120, 26, 100, 45, 102,
145, 171, 178, 135, 238, 2, 32, 239, 53, 61, 78, 56, 139, 134, 46,
212, 55, 39, 2, 3, 1, 0, 1, 163, 83, 48, 81, 48, 29, 6,
3, 85, 29, 14, 4, 22, 4, 20, 22, 217, 14, 167, 113, 102, 100,
7, 234, 117, 42, 153, 36, 99, 160, 163, 39, 151, 159, 181, 48, 31,
6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 22, 217, 14, 167,
113, 102, 100, 7, 234, 117, 42, 153, 36, 99, 160, 163, 39, 151, 159,
181, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4, 5, 48, 3,
1, 1, 255, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1,
11, 5, 0, 3, 130, 1, 1, 0, 124, 63, 26, 197, 170, 235, 130,
152, 65, 23, 47, 77, 128, 163, 203, 225, 192, 160, 236, 217, 174, 38,
32, 245, 235, 61, 238, 39, 254, 114, 31, 247, 28, 175, 76, 128, 82,
111, 95, 67, 186, 21, 149, 252, 153, 229, 193, 17, 94, 49, 102, 210,
29, 113, 227, 38, 251, 161, 238, 87, 140, 147, 27, 171, 73, 115, 181,
101, 200, 28, 2, 243, 194, 27, 77, 87, 195, 50, 67, 87, 184, 223,
79, 87, 148, 48, 11, 87, 79, 30, 153, 12, 53, 71, 60, 33, 232,
158, 32, 109, 90, 196, 104, 22, 31, 251, 86, 174, 133, 7, 146, 104,
111, 142, 215, 73, 140, 108, 226, 123, 36, 216, 2, 65, 177, 87, 47,
145, 62, 80, 137, 189, 122, 206, 175, 16, 52, 112, 233, 69, 248, 148,
221, 147, 40, 16, 104, 112, 87, 229, 228, 9, 108, 89, 129, 117, 141,
104, 23, 35, 113, 61, 22, 246, 73, 176, 254, 189, 7, 223, 49, 71,
194, 238, 211, 87, 166, 67, 172, 125, 63, 136, 68, 231, 213, 13, 61,
102, 14, 177, 131, 103, 9, 250, 198, 190, 153, 233, 75, 127, 79, 203,
163, 41, 68, 201, 215, 234, 167, 147, 15, 73, 6, 146, 119, 185, 133,
15, 40, 208, 103, 247, 149, 83, 185, 99, 10, 134, 89, 33, 179, 65,
143, 55, 37, 93, 139, 174, 64, 52, 22, 8, 128, 240, 93, 164, 135,
9, 217, 64, 54, 66, 245, 42, 148, 64};
// The public key of |kCertificateDer|.
const std::vector<uint8_t> kCertificateSpkiDer = {
48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1,
1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130,
1, 1, 0, 175, 103, 224, 10, 106, 96, 140, 64, 134, 186, 210, 5,
92, 160, 224, 117, 88, 148, 184, 148, 135, 242, 95, 65, 112, 75, 77,
80, 68, 216, 98, 95, 39, 219, 229, 176, 19, 25, 149, 142, 151, 1,
221, 192, 6, 7, 201, 133, 186, 45, 237, 28, 210, 126, 136, 190, 68,
242, 232, 131, 168, 236, 18, 236, 236, 163, 33, 130, 235, 131, 210, 49,
236, 108, 245, 182, 26, 249, 109, 223, 158, 33, 187, 222, 89, 151, 134,
213, 46, 198, 215, 57, 239, 143, 132, 108, 69, 106, 97, 158, 144, 13,
112, 226, 137, 186, 234, 91, 48, 97, 253, 248, 245, 123, 101, 183, 137,
183, 39, 115, 26, 19, 201, 248, 71, 210, 172, 110, 98, 136, 224, 103,
222, 212, 156, 219, 69, 50, 18, 85, 180, 83, 84, 209, 176, 62, 94,
166, 91, 99, 78, 59, 36, 23, 23, 152, 215, 145, 248, 5, 253, 240,
29, 42, 125, 130, 109, 243, 10, 175, 149, 169, 102, 61, 106, 63, 156,
17, 185, 134, 199, 84, 7, 99, 231, 161, 222, 146, 161, 16, 27, 247,
178, 137, 57, 111, 252, 132, 113, 190, 46, 75, 107, 243, 125, 1, 153,
133, 86, 88, 141, 187, 27, 13, 53, 74, 156, 169, 87, 82, 192, 169,
44, 101, 3, 145, 251, 83, 171, 123, 188, 141, 137, 120, 26, 100, 45,
102, 145, 171, 178, 135, 238, 2, 32, 239, 53, 61, 78, 56, 139, 134,
46, 212, 55, 39, 2, 3, 1, 0, 1};
// Arbitrary blob representing some signature.
const std::vector<uint8_t> kSignatureBlob(32, 55);
// Arbitrary blob of data.
const std::vector<uint8_t> kDataBlob(42, 77);
// Valid serialized KeyPermissions protobuf.
const std::vector<uint8_t> kArcKeyPermissionTrue = {10, 4, 8, 1, 16, 1};
const std::vector<uint8_t> kArcKeyPermissionFalse = {10, 2, 8, 1};
constexpr char kLabel[] = "object_label";
const brillo::Blob kId(10, 10);
} // anonymous namespace
// Fixture for chaps client tests.
class ChapsClientTest : public ::testing::Test {
public:
ChapsClientTest()
: chaps_mock_(/* is_initialized */ true),
chaps_client_(context_adaptor_.GetWeakPtr()) {}
uint32_t FakeGetCertificateBlob(const brillo::SecureBlob& isolate_credential,
uint64_t session_id,
uint64_t object_handle,
const std::vector<uint8_t>& attributes_in,
std::vector<uint8_t>* attributes_out) {
return ParseAttribute(kCertificateDer, attributes_in, attributes_out);
}
uint32_t FakeGetAttribute(const brillo::SecureBlob& isolate_credential,
uint64_t session_id,
uint64_t object_handle,
const std::vector<uint8_t>& attributes_in,
std::vector<uint8_t>* attributes_out) {
chaps::Attributes input;
input.Parse(attributes_in);
if (input.attributes()[0].type == CKA_VALUE)
return ParseAttribute(kKeyBlob, attributes_in, attributes_out);
return ParseAttribute(kArcKeyPermissionTrue, attributes_in, attributes_out);
}
uint32_t FakeGetAttributeWithoutArcPermission(
const brillo::SecureBlob& isolate_credential,
uint64_t session_id,
uint64_t object_handle,
const std::vector<uint8_t>& attributes_in,
std::vector<uint8_t>* attributes_out) {
chaps::Attributes input;
input.Parse(attributes_in);
if (input.attributes()[0].type == CKA_VALUE)
return ParseAttribute(kKeyBlob, attributes_in, attributes_out);
return ParseAttribute(kArcKeyPermissionFalse, attributes_in,
attributes_out);
}
protected:
void SetUp() override {
context_adaptor_.set_slot_for_tests(1);
ON_CALL(chaps_mock_, OpenSession(_, _, _, _))
.WillByDefault(DoAll(SetArgPointee<3>(kSessionId), Return(CKR_OK)));
ON_CALL(chaps_mock_, CloseSession(_, _)).WillByDefault(Return(CKR_OK));
ON_CALL(chaps_mock_, FindObjectsInit(_, _, _))
.WillByDefault(Return(CKR_OK));
ON_CALL(chaps_mock_, FindObjects(_, _, _, _))
.WillByDefault(DoAll(SetArgPointee<3>(kObjectList), Return(CKR_OK)));
ON_CALL(chaps_mock_, FindObjectsFinal(_, _)).WillByDefault(Return(CKR_OK));
ON_CALL(chaps_mock_, GetAttributeValue(_, _, _, _, _))
.WillByDefault(
Invoke(/* obj_ptr */ this, &ChapsClientTest::FakeGetAttribute));
}
::testing::NiceMock<::chaps::ChapsProxyMock> chaps_mock_;
ContextAdaptor context_adaptor_;
ChapsClient chaps_client_;
private:
uint32_t ParseAttribute(const std::vector<uint8_t>& blob,
const std::vector<uint8_t>& attributes_in,
std::vector<uint8_t>* attributes_out) {
chaps::Attributes parsed;
parsed.Parse(attributes_in);
parsed.attributes()[0].ulValueLen = blob.size();
if (parsed.attributes()[0].pValue) {
memcpy(parsed.attributes()[0].pValue, blob.data(), blob.size());
}
parsed.Serialize(attributes_out);
return CKR_OK;
}
};
TEST_F(ChapsClientTest, UsesSlotFromAdaptor) {
// Setup a fake slot in the cache.
uint64_t slot = 42;
context_adaptor_.set_slot_for_tests(slot);
// Expect chaps client will use the given slot.
EXPECT_CALL(chaps_mock_, OpenSession(_, Eq(slot), _, _));
// Call an operation that triggers slot usage.
chaps_client_.session_handle();
}
TEST_F(ChapsClientTest, ExportExistingEncryptionKey) {
// An existing key is prepared in fixture setup, expect no generation happens.
EXPECT_CALL(chaps_mock_, GenerateKey(_, _, _, _, _, _)).Times(0);
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify output.
ASSERT_TRUE(encryption_key.has_value());
std::vector<uint8_t> key(encryption_key->begin(), encryption_key->end());
EXPECT_EQ(kKeyBlob, key);
}
TEST_F(ChapsClientTest, ExportGeneratedEncryptionKey) {
// Expect no existing key is found and generation is called.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(kEmptyObjectList), Return(CKR_OK)));
EXPECT_CALL(chaps_mock_, GenerateKey(_, _, _, _, _, _))
.WillOnce(Return(CKR_OK));
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify output.
ASSERT_TRUE(encryption_key.has_value());
std::vector<uint8_t> key(encryption_key->begin(), encryption_key->end());
EXPECT_EQ(kKeyBlob, key);
}
TEST_F(ChapsClientTest, CachesExportedEncryptionKey) {
// Expect chaps is queried only once.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _)).Times(1);
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify exported key is cached in adaptor
ASSERT_TRUE(context_adaptor_.encryption_key().has_value());
std::vector<uint8_t> key(context_adaptor_.encryption_key()->begin(),
context_adaptor_.encryption_key()->end());
EXPECT_EQ(kKeyBlob, key);
// Verify exporting key again won't trigger more FindObject calls.
for (int i = 0; i < 10; ++i)
chaps_client_.ExportOrGenerateEncryptionKey();
}
TEST_F(ChapsClientTest, ReturnsCachedEncryptionKey) {
// Prepare the adaptor cache with a key.
brillo::SecureBlob in_key(kKeyBlob.begin(), kKeyBlob.end());
context_adaptor_.set_encryption_key(in_key);
// Expect chaps is never asked to find nor generate a key.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _)).Times(0);
EXPECT_CALL(chaps_mock_, GenerateKey(_, _, _, _, _, _)).Times(0);
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify exported key is what we prepared in adaptor cache.
ASSERT_TRUE(encryption_key.has_value());
std::vector<uint8_t> key(encryption_key->begin(), encryption_key->end());
EXPECT_EQ(kKeyBlob, key);
}
TEST_F(ChapsClientTest, InitializeSignature) {
// Expect the correct parameters are forwarded to chaps.
CK_MECHANISM_TYPE mechanism = CKM_RSA_PKCS;
CK_OBJECT_HANDLE handle = 42;
EXPECT_CALL(chaps_mock_, SignInit(_, _, Eq(mechanism), _, Eq(handle)));
bool result = chaps_client_.InitializeSignature(mechanism, handle);
ASSERT_TRUE(result);
}
TEST_F(ChapsClientTest, InitializeSignatureObeysKeyPermissions) {
CK_MECHANISM_TYPE mechanism = CKM_RSA_PKCS;
CK_OBJECT_HANDLE handle = 42;
EXPECT_CALL(chaps_mock_, GetAttributeValue(_, _, _, _, _))
.WillOnce(Invoke(/* obj_ptr */ this,
&ChapsClientTest::FakeGetAttributeWithoutArcPermission))
.WillOnce(Invoke(/* obj_ptr */ this,
&ChapsClientTest::FakeGetAttributeWithoutArcPermission))
.WillRepeatedly(
Invoke(/* obj_ptr */ this, &ChapsClientTest::FakeGetAttribute));
// The first call receives kArcKeyPermissionFalse and should fail.
bool result = chaps_client_.InitializeSignature(mechanism, handle);
ASSERT_FALSE(result);
// Following calls receive kArcKeyPermissionTrue and should work.
bool new_result = chaps_client_.InitializeSignature(mechanism, handle);
ASSERT_TRUE(new_result);
}
TEST_F(ChapsClientTest, UpdateSignature) {
// Expect the correct parameters are forwarded to chaps.
EXPECT_CALL(chaps_mock_, SignUpdate(_, _, Eq(kDataBlob)));
bool result = chaps_client_.UpdateSignature(kDataBlob);
ASSERT_TRUE(result);
}
TEST_F(ChapsClientTest, FinalizeSignature) {
// Expect the output is forwarded from chaps.
EXPECT_CALL(chaps_mock_, SignFinal(_, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<4>(kSignatureBlob), Return(CKR_OK)));
base::Optional<brillo::Blob> signature = chaps_client_.FinalizeSignature();
ASSERT_EQ(kSignatureBlob, signature);
}
TEST_F(ChapsClientTest, FindObjectHandlesInvalidSession) {
// Expect a retry if FindObjects returns CKR_SESSION_HANDLE_INVALID.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(DoAll(SetArgPointee<3>(kObjectList), Return(CKR_OK)));
// Call find object.
base::Optional<CK_OBJECT_HANDLE> handle =
chaps_client_.FindObject(CKO_CERTIFICATE, std::string(kLabel), kId);
// Verify the correct handle is returned.
ASSERT_TRUE(handle.has_value());
EXPECT_EQ(handle.value(), kObjectList[0]);
}
TEST_F(ChapsClientTest, ExportSubjectPublicKeyInfoHandlesInvalidSession) {
// Expect a retry if FindObjects returns CKR_SESSION_HANDLE_INVALID.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(DoAll(SetArgPointee<3>(kObjectList), Return(CKR_OK)));
EXPECT_CALL(chaps_mock_, GetAttributeValue(_, _, _, _, _))
.WillRepeatedly(
Invoke(/* obj_ptr */ this, &ChapsClientTest::FakeGetCertificateBlob));
// Call export SPKI.
base::Optional<brillo::Blob> spki =
chaps_client_.ExportSubjectPublicKeyInfo(std::string(kLabel), kId);
// Verify the correct blob is returned.
ASSERT_TRUE(spki.has_value());
EXPECT_EQ(kCertificateSpkiDer, spki.value());
}
// base::Optional<brillo::Blob> ExportSubjectPublicKeyInfo(
// const std::string& label, const brillo::Blob& id);
TEST_F(ChapsClientTest, FindKeyHandlesInvalidSession) {
// Expect a retry if FindObjects returns CKR_SESSION_HANDLE_INVALID.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(DoAll(SetArgPointee<3>(kObjectList), Return(CKR_OK)));
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify key is exported successfully.
ASSERT_TRUE(encryption_key.has_value());
std::vector<uint8_t> key(encryption_key->begin(), encryption_key->end());
EXPECT_EQ(kKeyBlob, key);
}
TEST_F(ChapsClientTest, GenerateKeyHandlesInvalidSession) {
// Expect a retry if GenerateKey returns CKR_SESSION_HANDLE_INVALID.
EXPECT_CALL(chaps_mock_, FindObjects(_, _, _, _))
.WillOnce(DoAll(SetArgPointee<3>(kEmptyObjectList), Return(CKR_OK)));
EXPECT_CALL(chaps_mock_, GenerateKey(_, _, _, _, _, _))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(Return(CKR_OK));
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify output.
ASSERT_TRUE(encryption_key.has_value());
std::vector<uint8_t> key(encryption_key->begin(), encryption_key->end());
EXPECT_EQ(kKeyBlob, key);
}
TEST_F(ChapsClientTest, GetAttributeHandlesInvalidSession) {
// Expect a retry if GetAttribute returns CKR_SESSION_HANDLE_INVALID.
EXPECT_CALL(chaps_mock_, GetAttributeValue(_, _, _, _, _))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillOnce(Return(CKR_SESSION_HANDLE_INVALID))
.WillRepeatedly(
Invoke(/* obj_ptr */ this, &ChapsClientTest::FakeGetAttribute));
// Call export key.
base::Optional<brillo::SecureBlob> encryption_key =
chaps_client_.ExportOrGenerateEncryptionKey();
// Verify output.
ASSERT_TRUE(encryption_key.has_value());
std::vector<uint8_t> key(encryption_key->begin(), encryption_key->end());
EXPECT_EQ(kKeyBlob, key);
}
} // namespace context
} // namespace keymaster
} // namespace arc