| // 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_crypto_operation.h" |
| |
| #include <cstdint> |
| #include <iterator> |
| #include <vector> |
| |
| #include <brillo/secure_blob.h> |
| #include <chaps/attributes.h> |
| #include <chaps/chaps_proxy_mock.h> |
| #include <chaps/pkcs11/pkcs11t.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "arc/keymaster/context/context_adaptor.h" |
| #include "arc/keymaster/context/crypto_operation.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}; |
| |
| // Arbitrary 32 byte key. |
| const std::vector<uint8_t> kKeyBlob(32, 99); |
| |
| // 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}; |
| |
| constexpr char kLabel[] = "object_label"; |
| |
| const brillo::Blob kId(10, 10); |
| |
| const MechanismDescription kDescription = kCkmRsaPkcsSign; |
| |
| } // anonymous namespace |
| |
| // Fixture for chaps client tests. |
| class ChapsCryptoOperationTest : public ::testing::Test { |
| public: |
| ChapsCryptoOperationTest() |
| : chaps_mock_(/* is_initialized */ true), |
| operation_(context_adaptor_.GetWeakPtr(), kLabel, kId) {} |
| |
| uint32_t FakeGetKeyBlob(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 parsed; |
| parsed.Parse(attributes_in); |
| std::vector<uint8_t> out_blob = parsed.attributes()[0].type == CKA_VALUE |
| ? kKeyBlob |
| : kArcKeyPermissionTrue; |
| parsed.attributes()[0].ulValueLen = out_blob.size(); |
| if (parsed.attributes()[0].pValue) { |
| memcpy(parsed.attributes()[0].pValue, out_blob.data(), out_blob.size()); |
| } |
| parsed.Serialize(attributes_out); |
| return CKR_OK; |
| } |
| |
| 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, |
| &ChapsCryptoOperationTest::FakeGetKeyBlob)); |
| ON_CALL(chaps_mock_, SignFinal(_, _, _, _, _)) |
| .WillByDefault(DoAll(SetArgPointee<4>(kSignatureBlob), Return(CKR_OK))); |
| } |
| |
| ::testing::NiceMock<::chaps::ChapsProxyMock> chaps_mock_; |
| ContextAdaptor context_adaptor_; |
| ChapsCryptoOperation operation_; |
| }; |
| |
| TEST_F(ChapsCryptoOperationTest, BeginForwardsLabelAndId) { |
| // Prepare an attributes list with the expected parameters. |
| CK_OBJECT_CLASS object_class = CKO_PRIVATE_KEY; |
| std::string mutable_label(kLabel); |
| CK_ATTRIBUTE findAttributes[] = { |
| {CKA_CLASS, &object_class, sizeof(object_class)}, |
| {CKA_LABEL, std::data(mutable_label), mutable_label.size()}, |
| {CKA_ID, const_cast<uint8_t*>(kId.data()), kId.size()}, |
| }; |
| chaps::Attributes parsed(findAttributes, std::size(findAttributes)); |
| std::vector<uint8_t> serialized_attributes; |
| parsed.Serialize(&serialized_attributes); |
| |
| // Expect chaps will receive the correct attributes. |
| EXPECT_CALL(chaps_mock_, FindObjectsInit(_, _, Eq(serialized_attributes))); |
| |
| // Call Begin. |
| operation_.Begin(kDescription); |
| } |
| |
| TEST_F(ChapsCryptoOperationTest, BeginUsesCorrectMechanism) { |
| EXPECT_CALL(chaps_mock_, SignInit(_, _, Eq(CKM_RSA_PKCS), _, _)); |
| operation_.Begin(kCkmRsaPkcsSign); |
| |
| EXPECT_CALL(chaps_mock_, SignInit(_, _, Eq(CKM_SHA256_RSA_PKCS), _, _)); |
| operation_.Begin(kCkmSha256RsaPkcsSign); |
| } |
| |
| TEST_F(ChapsCryptoOperationTest, Update) { |
| operation_.Begin(kDescription); |
| base::Optional<brillo::Blob> result = operation_.Update(kDataBlob); |
| |
| ASSERT_TRUE(result.has_value()); |
| ASSERT_TRUE(result->empty()); |
| } |
| |
| TEST_F(ChapsCryptoOperationTest, Finish) { |
| operation_.Begin(kDescription); |
| base::Optional<brillo::Blob> result = operation_.Finish(); |
| |
| ASSERT_TRUE(result.has_value()); |
| ASSERT_EQ(result.value(), kSignatureBlob); |
| } |
| |
| TEST_F(ChapsCryptoOperationTest, Abort) { |
| operation_.Begin(kDescription); |
| bool result = operation_.Abort(); |
| |
| ASSERT_TRUE(result); |
| } |
| |
| } // namespace context |
| } // namespace keymaster |
| } // namespace arc |