blob: 75a56d8667ae4b21f0e52bc328888f8440127c97 [file] [log] [blame]
// 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 "object_impl.h"
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "chaps_factory_mock.h"
#include "object_policy_mock.h"
using std::string;
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;
using ::testing::SetArgumentPointee;
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.
scoped_ptr<ObjectPolicyMock> scoped_policy_; // Owns next_policy_ until used.
scoped_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, (void*)"test", 4},
{2, (void*)"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, (void*)"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));
// Mofify attributes successfully.
EXPECT_EQ(CKR_OK, object_->SetAttributes(templ, 1));
EXPECT_EQ(CKO_PUBLIC_KEY, object_->GetObjectClass());
}
} // namespace chaps
int main(int argc, char** argv) {
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}