| // Copyright (c) 2012 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 "chaps/object_impl.h" |
| |
| #include <string> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "chaps/chaps_factory_mock.h" |
| #include "chaps/object_policy_mock.h" |
| |
| using std::string; |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::InvokeWithoutArgs; |
| using ::testing::Return; |
| using ::testing::SetArgPointee; |
| |
| namespace chaps { |
| |
| // Test fixture for an initialized ObjectImpl instance. |
| class TestObject : public ::testing::Test { |
| public: |
| TestObject() { |
| scoped_policy_.reset(CreatePolicy()); |
| next_policy_ = scoped_policy_.get(); |
| policy_ = NULL; |
| EXPECT_CALL(factory_, CreateObjectPolicy(_)) |
| .WillRepeatedly(InvokeWithoutArgs(this, &TestObject::GetPolicy)); |
| object_.reset(new ObjectImpl(&factory_)); |
| } |
| |
| protected: |
| ObjectPolicyMock* CreatePolicy() { |
| ObjectPolicyMock* policy = new ObjectPolicyMock(); |
| EXPECT_CALL(*policy, Init(_)).Times(AnyNumber()); |
| EXPECT_CALL(*policy, IsReadAllowed(_)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*policy, IsModifyAllowed(_, _)).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*policy, IsObjectComplete()).WillRepeatedly(Return(true)); |
| EXPECT_CALL(*policy, SetDefaultAttributes()).Times(AnyNumber()); |
| return policy; |
| } |
| ObjectPolicy* GetPolicy() { |
| policy_ = scoped_policy_.release(); |
| scoped_policy_.reset(CreatePolicy()); |
| next_policy_ = scoped_policy_.get(); |
| return policy_; |
| } |
| ChapsFactoryMock factory_; |
| ObjectPolicyMock* policy_; // The policy in use (if any). |
| ObjectPolicyMock* next_policy_; // The policy to be used next. |
| // Owns next_policy_ until used. |
| std::unique_ptr<ObjectPolicyMock> scoped_policy_; |
| std::unique_ptr<ObjectImpl> object_; |
| }; |
| |
| // Test that the Object class asserts when ChapsFactory fails. |
| TEST(DeathTest, FactoryFailure) { |
| ChapsFactoryMock factory; |
| ObjectPolicy* null_policy = NULL; |
| EXPECT_CALL(factory, CreateObjectPolicy(1)) |
| .WillRepeatedly(Return(null_policy)); |
| ObjectImpl obj(&factory); |
| obj.SetAttributeInt(CKA_CLASS, 1); |
| EXPECT_DEATH_IF_SUPPORTED(obj.FinalizeNewObject(), "Check failed"); |
| } |
| |
| // Test object lifecycle management. |
| TEST_F(TestObject, GetStage) { |
| EXPECT_EQ(kCreate, object_->GetStage()); |
| ObjectImpl object2(&factory_); |
| object2.SetAttributeInt(CKA_CLASS, CKO_PUBLIC_KEY); |
| EXPECT_EQ(CKR_OK, object_->Copy(&object2)); |
| EXPECT_EQ(kCopy, object_->GetStage()); |
| EXPECT_EQ(CKR_OK, object_->FinalizeNewObject()); |
| EXPECT_EQ(kModify, object_->GetStage()); |
| } |
| |
| // Perform a sanity check for object size. |
| TEST_F(TestObject, GetSize) { |
| EXPECT_EQ(0, object_->GetSize()); |
| object_->SetAttributeString(1, string(20, 'a')); |
| EXPECT_LT(20, object_->GetSize()); |
| } |
| |
| // Test the convenience methods for common attributes. |
| TEST_F(TestObject, BuiltInAttributes) { |
| object_->SetAttributeInt(CKA_CLASS, CKO_PUBLIC_KEY); |
| object_->SetAttributeBool(CKA_TOKEN, true); |
| object_->SetAttributeBool(CKA_MODIFIABLE, true); |
| object_->SetAttributeBool(CKA_PRIVATE, false); |
| EXPECT_EQ(CKO_PUBLIC_KEY, object_->GetObjectClass()); |
| EXPECT_TRUE(object_->IsTokenObject()); |
| EXPECT_TRUE(object_->IsModifiable()); |
| EXPECT_FALSE(object_->IsPrivate()); |
| } |
| |
| // Test basic consistency for attribute manipulation. |
| TEST_F(TestObject, AttributeConsistency) { |
| // [G|S]etAttributeInt |
| EXPECT_FALSE(object_->IsAttributePresent(1)); |
| EXPECT_EQ(0, object_->GetAttributeInt(1, 0)); |
| object_->SetAttributeInt(1, 2); |
| EXPECT_TRUE(object_->IsAttributePresent(1)); |
| EXPECT_EQ(2, object_->GetAttributeInt(1, 0)); |
| object_->SetAttributeString(1, string(1, 0xA)); |
| EXPECT_EQ(0xA, object_->GetAttributeInt(1, 0)); |
| object_->SetAttributeString(1, string(2, 0xA)); |
| EXPECT_EQ(0xA0A, object_->GetAttributeInt(1, 0)); |
| object_->SetAttributeString(1, string(3, 0xA)); |
| EXPECT_EQ(0, object_->GetAttributeInt(1, 0)); |
| object_->SetAttributeString(1, string(4, 0xA)); |
| EXPECT_EQ(0xA0A0A0A, object_->GetAttributeInt(1, 0)); |
| // [G|S]etAttributeBool |
| EXPECT_FALSE(object_->IsAttributePresent(2)); |
| EXPECT_FALSE(object_->GetAttributeBool(2, false)); |
| object_->SetAttributeBool(2, true); |
| EXPECT_TRUE(object_->IsAttributePresent(2)); |
| EXPECT_TRUE(object_->GetAttributeBool(2, false)); |
| // [G|S]etAttributeString |
| EXPECT_FALSE(object_->IsAttributePresent(3)); |
| EXPECT_EQ("", object_->GetAttributeString(3)); |
| object_->SetAttributeString(3, "test"); |
| EXPECT_TRUE(object_->IsAttributePresent(3)); |
| EXPECT_EQ("test", object_->GetAttributeString(3)); |
| // RemoveAttribute |
| object_->RemoveAttribute(3); |
| EXPECT_FALSE(object_->IsAttributePresent(3)); |
| // [G|S]etAttributes |
| CK_ULONG val = 0x1234; |
| CK_ATTRIBUTE templ[] = {{1, &val, sizeof(CK_ULONG)}}; |
| EXPECT_EQ(CKR_OK, object_->SetAttributes(templ, 1)); |
| EXPECT_EQ(0x1234, object_->GetAttributeInt(1, 0)); |
| CK_ULONG val2 = 0; |
| CK_ATTRIBUTE templ2[] = {{1, &val2, 17}}; |
| EXPECT_EQ(CKR_OK, object_->GetAttributes(templ2, 1)); |
| EXPECT_EQ(sizeof(CK_ULONG), templ2[0].ulValueLen); |
| EXPECT_EQ(0x1234, val2); |
| } |
| |
| // Test object policy assignment and validation when finalizing. |
| TEST_F(TestObject, FinalizeNewObject) { |
| // Finalize before setting object class. |
| EXPECT_EQ(CKR_TEMPLATE_INCOMPLETE, object_->FinalizeNewObject()); |
| // Finalize after setting read-only attribute. |
| EXPECT_CALL(*next_policy_, IsModifyAllowed(1, "test")) |
| .WillRepeatedly(Return(false)); |
| CK_OBJECT_CLASS classval = CKO_PUBLIC_KEY; |
| CK_ATTRIBUTE attr[] = {{CKA_CLASS, &classval, sizeof(classval)}, |
| {1, const_cast<char*>("test"), 4}, |
| {2, const_cast<char*>("test2"), 5}}; |
| object_->SetAttributes(attr, 3); |
| EXPECT_EQ(CKR_ATTRIBUTE_READ_ONLY, object_->FinalizeNewObject()); |
| // Finalize before object is complete. |
| EXPECT_CALL(*next_policy_, IsModifyAllowed(1, "test")) |
| .WillRepeatedly(Return(false)); |
| EXPECT_CALL(*next_policy_, IsObjectComplete()) |
| .WillOnce(Return(false)) |
| .WillRepeatedly(Return(true)); |
| CK_ATTRIBUTE attr2[] = {{1, const_cast<char*>("test3"), 5}}; |
| object_->SetAttributes(attr2, 1); |
| EXPECT_EQ(CKR_TEMPLATE_INCOMPLETE, object_->FinalizeNewObject()); |
| EXPECT_EQ(CKR_OK, object_->FinalizeNewObject()); |
| } |
| |
| // Test GetAttributes in more detail. |
| TEST_F(TestObject, GetAttributes) { |
| EXPECT_CALL(*next_policy_, IsReadAllowed(CKA_CLASS)) |
| .WillOnce(Return(false)) |
| .WillRepeatedly(Return(true)); |
| // Attempt to read an attribute before it has been set. |
| CK_ATTRIBUTE templ[] = {{CKA_CLASS, NULL, 0}}; |
| EXPECT_EQ(CKR_ATTRIBUTE_TYPE_INVALID, object_->GetAttributes(templ, 1)); |
| EXPECT_EQ(-1, templ[0].ulValueLen); |
| // Attempt to read a read-only attribute (IsReadAllowed returns false once). |
| object_->SetAttributeInt(CKA_CLASS, CKO_PUBLIC_KEY); |
| object_->FinalizeNewObject(); |
| EXPECT_EQ(CKR_ATTRIBUTE_SENSITIVE, object_->GetAttributes(templ, 1)); |
| EXPECT_EQ(-1, templ[0].ulValueLen); |
| // Read an attribute's length (pValue == NULL) successfully. |
| EXPECT_EQ(CKR_OK, object_->GetAttributes(templ, 1)); |
| EXPECT_EQ(sizeof(CK_ULONG), templ[0].ulValueLen); |
| // Read an attribute with not enough buffer. |
| CK_ULONG val = 0; |
| templ[0].ulValueLen = 1; |
| templ[0].pValue = &val; |
| EXPECT_EQ(CKR_BUFFER_TOO_SMALL, object_->GetAttributes(templ, 1)); |
| EXPECT_EQ(-1, templ[0].ulValueLen); |
| // Read an attribute successfully. |
| templ[0].ulValueLen = sizeof(CK_ULONG); |
| EXPECT_EQ(CKR_OK, object_->GetAttributes(templ, 1)); |
| EXPECT_EQ(CKO_PUBLIC_KEY, val); |
| } |
| |
| // Test SetAttributes in more detail. |
| TEST_F(TestObject, SetAttributes) { |
| CK_ULONG val = CKO_PUBLIC_KEY; |
| CK_ATTRIBUTE templ[] = {{CKA_CLASS, &val, sizeof(CK_ULONG)}}; |
| // Modify attributes before finalizing (object creation stage). |
| EXPECT_EQ(CKR_OK, object_->SetAttributes(templ, 1)); |
| EXPECT_EQ(CKR_OK, object_->FinalizeNewObject()); |
| // Attempt to modify read-only attributes. |
| EXPECT_CALL(*policy_, IsModifyAllowed(_, _)) |
| .WillOnce(Return(false)) |
| .WillRepeatedly(Return(true)); |
| EXPECT_EQ(CKR_ATTRIBUTE_READ_ONLY, object_->SetAttributes(templ, 1)); |
| // Modify attributes successfully. |
| EXPECT_EQ(CKR_OK, object_->SetAttributes(templ, 1)); |
| EXPECT_EQ(CKO_PUBLIC_KEY, object_->GetObjectClass()); |
| // Attempt to set with invalid length; specifically, with the length value |
| // that is used to indicate an error on C_GetAttributeValue (so if an |
| // application re-used the CK_ATTRIBUTE template without checking/updating |
| // the length, this is what arrives). |
| CK_BYTE label[] = "label"; |
| CK_ATTRIBUTE invalid[] = {{CKA_LABEL, &label, (CK_ULONG)-1}}; |
| EXPECT_EQ(CKR_ATTRIBUTE_VALUE_INVALID, object_->SetAttributes(invalid, 1)); |
| } |
| |
| } // namespace chaps |