diff options
Diffstat (limited to 'SoftHSMv2/src/lib/object_store/test')
26 files changed, 6177 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp new file mode 100644 index 0000000..2cc8360 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectStoreTests.cpp + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "DBObjectStoreTests.h" + +#include <cstdio> + +#ifndef HAVE_SQLITE3_H +#error expected sqlite3 to be available +#endif + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_newly_created_object_store); + +void test_a_newly_created_object_store::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); + + ObjectStoreToken::selectBackend("db"); + + store = new ObjectStore("testdir"); + nulltoken = NULL; +} + +void test_a_newly_created_object_store::tearDown() +{ + delete store; + + ObjectStoreToken::selectBackend("file"); + +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + + +void test_a_newly_created_object_store::contains_no_items() +{ + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)0); +} + +void test_a_newly_created_object_store::can_create_a_new_token() +{ + ByteString label1 = "DEADC0FFEE"; + + ObjectStoreToken *token1 = store->newToken(label1); + CPPUNIT_ASSERT(token1 != nulltoken); + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)1); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_newly_created_object_store_containing_two_tokens); + + +void test_a_newly_created_object_store_containing_two_tokens::setUp() +{ + test_a_newly_created_object_store::setUp(); + + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + + ObjectStoreToken* token1 = store->newToken(label1); + CPPUNIT_ASSERT(token1 != nulltoken); + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)1); + + ObjectStoreToken* token2 = store->newToken(label2); + CPPUNIT_ASSERT(token2 != nulltoken); + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)2); +} + +void test_a_newly_created_object_store_containing_two_tokens::tearDown() +{ + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + CPPUNIT_ASSERT(store->destroyToken(token1)); + CPPUNIT_ASSERT(store->destroyToken(token2)); + + test_a_newly_created_object_store::tearDown(); +} + +void test_a_newly_created_object_store_containing_two_tokens::has_two_tokens() +{ + CPPUNIT_ASSERT_EQUAL(store->getTokenCount(), (size_t)2); +} + +void test_a_newly_created_object_store_containing_two_tokens::can_access_both_tokens() +{ + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + + CPPUNIT_ASSERT(token1 != nulltoken); + CPPUNIT_ASSERT(token2 != nulltoken); +} + +void test_a_newly_created_object_store_containing_two_tokens::assigned_labels_correctly_to_tokens() +{ + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + + ByteString retrieveLabel1, retrieveLabel2; + + CPPUNIT_ASSERT(token1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(token2->getTokenLabel(retrieveLabel2)); + + CPPUNIT_ASSERT(label1 == retrieveLabel1 || label1 == retrieveLabel2); + CPPUNIT_ASSERT(label2 == retrieveLabel1 || label2 == retrieveLabel2); + CPPUNIT_ASSERT(label1 != label2); +} + +void test_a_newly_created_object_store_containing_two_tokens::assigned_a_unique_serial_number_to_each_token() +{ + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store->getToken(0); + ObjectStoreToken* token2 = store->getToken(1); + + ByteString retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(token1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(token2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); +} diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h new file mode 100644 index 0000000..7d100c8 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectStoreTests.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectStoreTests.h + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBOBJECTSTORETESTS_H +#define _SOFTHSM_V2_DBOBJECTSTORETESTS_H + +#include <cppunit/extensions/HelperMacros.h> +#include "ObjectStore.h" +#include "ObjectStoreToken.h" + +class test_a_newly_created_object_store : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_newly_created_object_store); + CPPUNIT_TEST(contains_no_items); + CPPUNIT_TEST(can_create_a_new_token); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void contains_no_items(); + void can_create_a_new_token(); +protected: + ObjectStore *store; + ObjectStoreToken *nulltoken; + +private: +}; + +class test_a_newly_created_object_store_containing_two_tokens : public test_a_newly_created_object_store +{ + CPPUNIT_TEST_SUITE(test_a_newly_created_object_store_containing_two_tokens); + CPPUNIT_TEST(has_two_tokens); + CPPUNIT_TEST(can_access_both_tokens); + CPPUNIT_TEST(assigned_labels_correctly_to_tokens); + CPPUNIT_TEST(assigned_a_unique_serial_number_to_each_token); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void has_two_tokens(); + void can_access_both_tokens(); + void assigned_labels_correctly_to_tokens(); + void assigned_a_unique_serial_number_to_each_token(); +}; + +#endif // !_SOFTHSM_V2_DBOBJECTSTORETESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp new file mode 100644 index 0000000..d856b06 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.cpp @@ -0,0 +1,816 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectTests.cpp + + Contains test cases to test the database token object implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "DBObjectTests.h" +#include "DBObject.h" + +#include <cstdio> + +#ifndef HAVE_SQLITE3_H +#error expected sqlite3 to be available +#endif + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_dbobject); + +void test_a_dbobject::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); + connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != NULL); + CPPUNIT_ASSERT(connection->connect("<1>")); + connection->setBusyTimeout(10); + + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite)); + CPPUNIT_ASSERT(testObject.createTables()); + CPPUNIT_ASSERT(testObject.commitTransaction()); + + connection2 = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection2 != NULL); + CPPUNIT_ASSERT(connection2->connect("<2>")); + connection2->setBusyTimeout(10); +} + +void test_a_dbobject::tearDown() +{ + CPPUNIT_ASSERT(connection != NULL); + connection->close(); + delete connection; + + CPPUNIT_ASSERT(connection2 != NULL); + connection2->close(); + delete connection2; + +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void test_a_dbobject::should_be_insertable() +{ + DBObject tokenObject(connection); + CPPUNIT_ASSERT(!tokenObject.isValid()); + CPPUNIT_ASSERT(tokenObject.insert()); + CPPUNIT_ASSERT(tokenObject.isValid()); + CPPUNIT_ASSERT_EQUAL(tokenObject.objectId(), (long long)1); +} + +void test_a_dbobject::should_be_selectable() +{ + should_be_insertable(); + + DBObject tokenObject(connection); + CPPUNIT_ASSERT(tokenObject.find(1)); + CPPUNIT_ASSERT(tokenObject.isValid()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_dbobject_with_an_object); + +void test_a_dbobject_with_an_object::setUp() +{ + test_a_dbobject::setUp(); + DBObject tokenObject(connection); + CPPUNIT_ASSERT(tokenObject.startTransaction(DBObject::ReadWrite)); + CPPUNIT_ASSERT(!tokenObject.isValid()); + CPPUNIT_ASSERT(tokenObject.insert()); + CPPUNIT_ASSERT(tokenObject.isValid()); + CPPUNIT_ASSERT_EQUAL(tokenObject.objectId(), (long long)1); + CPPUNIT_ASSERT(tokenObject.commitTransaction()); + +} + +void test_a_dbobject_with_an_object::tearDown() +{ + test_a_dbobject::tearDown(); +} + +void test_a_dbobject_with_an_object::should_store_boolean_attributes() +{ + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + bool value2 = false; + bool value3 = true; + bool value4 = true; + bool value5 = false; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SENSITIVE, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_EXTRACTABLE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_NEVER_EXTRACTABLE, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr5)); + } + + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SENSITIVE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_EXTRACTABLE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_NEVER_EXTRACTABLE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue()); + CPPUNIT_ASSERT(!testObject.getAttribute(CKA_SENSITIVE).getBooleanValue()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).getBooleanValue()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).getBooleanValue()); + CPPUNIT_ASSERT(!testObject.getAttribute(CKA_SIGN).getBooleanValue()); + + bool value6 = true; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VERIFY, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).isBooleanAttribute()); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_VERIFY).getBooleanValue(), value6); + CPPUNIT_ASSERT_EQUAL(testObject.getBooleanValue(CKA_VERIFY, false), value6); + } +} + + +void test_a_dbobject_with_an_object::should_store_unsigned_long_attributes() +{ + // Add unsigned long attributes to the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + unsigned long value1 = 0x12345678; + unsigned long value2 = 0x87654321; + unsigned long value3 = 0x01010101; + unsigned long value4 = 0x10101010; + unsigned long value5 = 0xABCDEF; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS_BITS, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_AUTH_PIN_FLAGS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBPRIME_BITS, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_KEY_TYPE, attr5)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_AUTH_PIN_FLAGS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBPRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_KEY_TYPE)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).isUnsignedLongAttribute()); + + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_MODULUS_BITS).getUnsignedLongValue(), (unsigned long)0x12345678); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue(), (unsigned long)0x87654321); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).getUnsignedLongValue(), (unsigned long)0x01010101); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_SUBPRIME_BITS).getUnsignedLongValue(), (unsigned long)0x10101010); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_KEY_TYPE).getUnsignedLongValue(), (unsigned long)0xABCDEF); + + unsigned long value6 = 0x90909090; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_CLASS, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_CLASS).getUnsignedLongValue(), value6); + CPPUNIT_ASSERT_EQUAL(testObject.getUnsignedLongValue(CKA_CLASS, 0x0), value6); + } +} + +void test_a_dbobject_with_an_object::should_store_binary_attributes() +{ + ByteString value1 = "010203040506070809"; + ByteString value2 = "ABABABABABABABABABABABABABABABABAB"; + unsigned long value3 = 0xBDED; + ByteString value4 = "98A7E5D798A7E5D798A7E5D798A7E5D798A7E5D798A7E5D7"; + ByteString value5 = "ABCDABCDABCDABCDABCDABCDABCDABCD"; + + // Create the test object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_COEFFICIENT, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PUBLIC_EXPONENT, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr5)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_COEFFICIENT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PUBLIC_EXPONENT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).getByteStringValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).getByteStringValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value5); + + ByteString value6 = "909090908080808080807070707070FF"; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ISSUER, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ISSUER).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getByteStringValue(CKA_ISSUER) == value6); + } +} + +void test_a_dbobject_with_an_object::should_store_mechtypeset_attributes() +{ + + // Create the test object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + std::set<CK_MECHANISM_TYPE> set; + set.insert(CKM_SHA256); + set.insert(CKM_SHA512); + OSAttribute attr(set); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + std::set<CK_MECHANISM_TYPE> retrieved = + testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue(); + + CPPUNIT_ASSERT(retrieved.size() == 2); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA256) != retrieved.end()); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA384) == retrieved.end()); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA512) != retrieved.end()); + } +} + +void test_a_dbobject_with_an_object::should_store_attrmap_attributes() +{ + bool value1 = true; + unsigned long value2 = 0x87654321; + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + + // Create the test object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattr; + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_TOKEN, attr1)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_PRIME_BITS, attr2)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_VALUE, attr3)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_ALLOWED_MECHANISMS, attr4)); + OSAttribute attra(mattr); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_WRAP_TEMPLATE, attra)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_WRAP_TEMPLATE)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_UNWRAP_TEMPLATE)); + + std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattrb = + testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue(); + CPPUNIT_ASSERT(mattrb.size() == 4); + CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(mattrb.find(CKA_VALUE) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(mattrb.find(CKA_ALLOWED_MECHANISMS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + } +} + +void test_a_dbobject_with_an_object::should_store_mixed_attributes() +{ + bool value1 = true; + unsigned long value2 = 0x87654321; + unsigned long value3 = 0xBDEBDBED; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + + // Create the test object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue()); + CPPUNIT_ASSERT_EQUAL(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue(), value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + } +} + +void test_a_dbobject_with_an_object::should_store_double_attributes() +{ + bool value1 = true; + bool value1a = false; + + // Create the test object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue()); + + OSAttribute attr1(value1a); + + // Change the attributes + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1)); + + // Check the attributes + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == value1a); + } + + // Now re-read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == value1a); + } +} + +void test_a_dbobject_with_an_object::can_refresh_attributes() +{ + bool value1 = true; + bool value1a = false; + ByteString value2 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value2a = "466487346943785684957634"; + ByteString value3 = "0102010201020102010201020102010201020102"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + std::set<CK_MECHANISM_TYPE> value4a; + value4a.insert(CKM_SHA384); + value4a.insert(CKM_SHA512); + + // Create the test object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr4(value4); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + } + + // Now read back the object + { + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + OSAttribute attr1(value1a); + OSAttribute attr2(value2a); + OSAttribute attr4(value4a); + + // Change the attributes + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + + // Check the attributes + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Open the object a second time + DBObject testObject2(connection); + CPPUNIT_ASSERT(testObject2.find(1)); + CPPUNIT_ASSERT(testObject2.isValid()); + + // Check the attributes on the second instance + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SIGN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SUBJECT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SIGN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_SUBJECT).getByteStringValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Add an attribute on the second object + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr3)); + + // Check the attribute + CPPUNIT_ASSERT(testObject2.attributeExists(CKA_ID)); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value3); + + // Now check that the first instance also knows about it + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ID)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value3); + } +} + +void test_a_dbobject_with_an_object::should_cleanup_statements_during_transactions() +{ + // Create an object for accessing object 1 on the first connection. + DBObject testObject(connection); + // check transaction start(ro)/abort sequence + CPPUNIT_ASSERT(testObject.startTransaction(OSObject::ReadOnly)); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + CPPUNIT_ASSERT(testObject.abortTransaction()); +} + +void test_a_dbobject_with_an_object::should_use_transactions() +{ + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + unsigned long value3 = 0xBDEBDBED; + ByteString value4 = "AAAAAAAAAAAAAAAFFFFFFFFFFFFFFF"; + std::set<CK_MECHANISM_TYPE> value5; + value5.insert(CKM_SHA256); + value5.insert(CKM_SHA512); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5)); + + // Create secondary instance for the same object. + // This needs to have a different connection to the database to simulate + // another process accessing the data. + DBObject testObject2(connection2); + CPPUNIT_ASSERT(testObject2.find(1)); + CPPUNIT_ASSERT(testObject2.isValid()); + + // Check that it has the same attributes + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // Check that the attributes have the same values as set on testObject. + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5); + + // New values + bool value1a = false; + unsigned long value2a = 0x12345678; + unsigned long value3a = 0xABABABAB; + ByteString value4a = "EDEDEDEDEDEDEDEDEDEDEDEDEDEDED"; + std::set<CK_MECHANISM_TYPE> value5a; + value5a.insert(CKM_SHA384); + value5a.insert(CKM_SHA512); + + OSAttribute attr1a(value1a); + OSAttribute attr2a(value2a); + OSAttribute attr3a(value3a); + OSAttribute attr4a(value4a); + OSAttribute attr5a(value5a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5a)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); + + // Verify that they are unchanged on the other instance + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5); + + // Commit the transaction + CPPUNIT_ASSERT(testObject.commitTransaction()); + + // Verify that non-modifiable attributes did not propagate but modifiable attributes + // have now changed on the other instance + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // NOTE: 3 attributes below cannot be modified after creation and therefore are not required to propagate. + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() != value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() != value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() != value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() != value5a); + + // CKA_ID attribute can be modified after creation and therefore should have propagated. + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == value4a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(DBObject::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ID, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr5)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5); + + // Create a fresh third instance for the same object to force the data to be retrieved from the database. + DBObject testObject3(connection2); + CPPUNIT_ASSERT(testObject3.find(1)); + CPPUNIT_ASSERT(testObject3.isValid()); + + // Verify that they are unchanged on the other instance, while the transaction is still in progress. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // Verify that the attributes from the database are still hodling the same value as when the transaction started. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); + + // Abort the transaction + CPPUNIT_ASSERT(testObject.abortTransaction()); + + // Verify that after aborting the transaction the values in testObject have reverted back to their + // original state. + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // After aborting a transaction the testObject should be back to pre transaction state. + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); + + // Verify that testObject3 still has the original values. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + // Verify that testObject3 still has the original values. + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_VALUE_BITS).getUnsignedLongValue() == value3a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ID).getByteStringValue() == value4a); + CPPUNIT_ASSERT(testObject3.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value5a); +} + +void test_a_dbobject_with_an_object::should_fail_to_delete() +{ + DBObject testObject(connection); + CPPUNIT_ASSERT(testObject.find(1)); + CPPUNIT_ASSERT(testObject.isValid()); + // We don't attach the object to a token, and therefore should not be able to destroy it. + CPPUNIT_ASSERT(!testObject.destroyObject()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h new file mode 100644 index 0000000..136fa81 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBObjectTests.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBObjectTests.h + + Contains test cases to test the database token object implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBOBJECTTESTS_H +#define _SOFTHSM_V2_DBOBJECTTESTS_H + +#include <cppunit/extensions/HelperMacros.h> +#include "DB.h" + +class test_a_dbobject : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_dbobject); + CPPUNIT_TEST(should_be_insertable); + CPPUNIT_TEST(should_be_selectable); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void should_be_insertable(); + void should_be_selectable(); + +protected: + DB::Connection *connection; + DB::Connection *connection2; + +private: +}; + +class test_a_dbobject_with_an_object : public test_a_dbobject +{ + CPPUNIT_TEST_SUITE(test_a_dbobject_with_an_object); + CPPUNIT_TEST(should_store_boolean_attributes); + CPPUNIT_TEST(should_store_unsigned_long_attributes); + CPPUNIT_TEST(should_store_binary_attributes); + CPPUNIT_TEST(should_store_mechtypeset_attributes); + CPPUNIT_TEST(should_store_attrmap_attributes); + CPPUNIT_TEST(should_store_mixed_attributes); + CPPUNIT_TEST(should_store_double_attributes); + CPPUNIT_TEST(can_refresh_attributes); + CPPUNIT_TEST(should_cleanup_statements_during_transactions); + CPPUNIT_TEST(should_use_transactions); + CPPUNIT_TEST(should_fail_to_delete); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void should_store_boolean_attributes(); + void should_store_unsigned_long_attributes(); + void should_store_binary_attributes(); + void should_store_mechtypeset_attributes(); + void should_store_attrmap_attributes(); + void should_store_mixed_attributes(); + void should_store_double_attributes(); + void can_refresh_attributes(); + void should_cleanup_statements_during_transactions(); + void should_use_transactions(); + void should_fail_to_delete(); +}; + +#endif // !_SOFTHSM_V2_DBOBJECTTESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp new file mode 100644 index 0000000..d787a83 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTests.cpp @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTests.cpp + + Contains lowest level test cases for the database backend implementation. + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "DBTests.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db); + +static int dummy_print(const char *, va_list ) +{ + return 0; +} + +void test_a_db::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); + null = NULL; +} + +void test_a_db::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void test_a_db::checks_for_empty_connection_parameters() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + DB::Connection *connection = DB::Connection::Create("","TestToken"); + CPPUNIT_ASSERT_EQUAL(connection, null); + + connection = DB::Connection::Create("testdir",""); + CPPUNIT_ASSERT_EQUAL(connection, null); + + connection = DB::Connection::Create("",""); + CPPUNIT_ASSERT_EQUAL(connection, null); + + DB::setLogErrorHandler(eh); +} + +void test_a_db::can_be_connected_to_database() +{ + + DB::Connection *connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != null); + bool isConnected = connection->connect(); + delete connection; + CPPUNIT_ASSERT(isConnected); +#ifndef _WIN32 + CPPUNIT_ASSERT_EQUAL(system("test -f ./testdir/TestToken"), 0); +#else + CPPUNIT_ASSERT(GetFileAttributes("testdir\\TestToken") != INVALID_FILE_ATTRIBUTES); +#endif +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection); + +void test_a_db_with_a_connection::setUp() +{ + test_a_db::setUp(); + connection = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection != null); + CPPUNIT_ASSERT(connection->connect()); +} + +void test_a_db_with_a_connection::tearDown() +{ + CPPUNIT_ASSERT(connection != null); + connection->close(); + delete connection; + test_a_db::tearDown(); +} + +void test_a_db_with_a_connection::can_prepare_statements() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT(statement.isValid()); +} + +void test_a_db_with_a_connection::can_perform_statements() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + // only expect a single row in the result, so nextRow should now fail + CPPUNIT_ASSERT(!result.nextRow()); +} + +void test_a_db_with_a_connection::maintains_correct_refcounts() +{ + DB::Statement statement = connection->prepare("PRAGMA database_list;"); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); + { + DB::Statement statement1 = statement; + DB::Statement statement2 = statement; + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 3); + CPPUNIT_ASSERT(statement1.isValid()); + CPPUNIT_ASSERT(statement2.isValid()); + } + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); + + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // Statement is referenced by the result because it provides the query record cursor state. + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 2); + + result = DB::Result(); + CPPUNIT_ASSERT_EQUAL(statement.refcount(), 1); +} +void test_a_db_with_a_connection::can_create_tables() +{ + CPPUNIT_ASSERT(!connection->tableExists("object")); + DB::Statement cr_object = connection->prepare("create table object (id integer primary key autoincrement);"); + CPPUNIT_ASSERT(connection->execute(cr_object)); + CPPUNIT_ASSERT(connection->tableExists("object")); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables); + +void test_a_db_with_a_connection_with_tables::setUp() +{ + test_a_db_with_a_connection::setUp(); + can_create_tables(); + + // attribute_text + CPPUNIT_ASSERT(!connection->tableExists("attribute_text")); + DB::Statement cr_attr_text = connection->prepare( + "create table attribute_text (" + "value text," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_text)); + CPPUNIT_ASSERT(connection->tableExists("attribute_text")); + + // attribute_integer + CPPUNIT_ASSERT(!connection->tableExists("attribute_integer")); + DB::Statement cr_attr_integer = connection->prepare( + "create table attribute_integer (" + "value integer," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_integer)); + CPPUNIT_ASSERT(connection->tableExists("attribute_integer")); + + // attribute_blob + CPPUNIT_ASSERT(!connection->tableExists("attribute_blob")); + DB::Statement cr_attr_blob = connection->prepare( + "create table attribute_blob (" + "value blob," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_blob)); + CPPUNIT_ASSERT(connection->tableExists("attribute_blob")); + + // attribute_boolean + CPPUNIT_ASSERT(!connection->tableExists("attribute_boolean")); + DB::Statement cr_attr_boolean = connection->prepare( + "create table attribute_boolean (" + "value boolean," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_boolean)); + CPPUNIT_ASSERT(connection->tableExists("attribute_boolean")); + + // attribute_datetime + CPPUNIT_ASSERT(!connection->tableExists("attribute_datetime")); + DB::Statement cr_attr_datetime = connection->prepare( + "create table attribute_datetime (" + "value datetime," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_datetime)); + CPPUNIT_ASSERT(connection->tableExists("attribute_datetime")); + + // attribute_real + CPPUNIT_ASSERT(!connection->tableExists("attribute_real")); + DB::Statement cr_attr_real = connection->prepare( + "create table attribute_real (" + "value real," + "type integer," + "object_id integer references object(id) on delete cascade," + "id integer primary key autoincrement)" + ); + CPPUNIT_ASSERT(connection->execute(cr_attr_real)); + CPPUNIT_ASSERT(connection->tableExists("attribute_real")); +} + +void test_a_db_with_a_connection_with_tables::tearDown() +{ + test_a_db_with_a_connection::tearDown(); +} + +void test_a_db_with_a_connection_with_tables::can_insert_records() +{ + DB::Statement statement = connection->prepare("insert into object default values"); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + statement = connection->prepare( + "insert into attribute_text (value,type,object_id) values ('%s',%d,%lld)", + "testing testing testing", + 1234, + object_id); + CPPUNIT_ASSERT(connection->execute(statement)); +} + +void test_a_db_with_a_connection_with_tables::can_retrieve_records() +{ + can_insert_records(); + + DB::Statement statement = connection->prepare( + "select value from attribute_text as t where t.type=%d", + 1234); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), std::string("testing testing testing")); +} + +void test_a_db_with_a_connection_with_tables::can_cascade_delete_objects_and_attributes() +{ + can_insert_records(); + + DB::Statement statement = connection->prepare("select id from object"); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); + + statement = connection->prepare("delete from object where id=%lld",object_id); + CPPUNIT_ASSERT(connection->execute(statement)); + + statement = connection->prepare("select * from attribute_text where object_id=%lld",object_id); + result = connection->perform(statement); + + // Check cascade delete was successful. + CPPUNIT_ASSERT(!result.isValid()); +} + + +void test_a_db_with_a_connection_with_tables::can_update_text_attribute() +{ + can_insert_records(); + + // query all objects + DB::Statement statement = connection->prepare("select id from object"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); // field indices start at 1 + + statement = connection->prepare( + "update attribute_text set value='test test test' where type=%d and object_id=%lld", + 1234, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); +} + +void test_a_db_with_a_connection_with_tables::can_update_text_attribute_bound_value() +{ + can_insert_records(); + + // query all objects + DB::Statement statement = connection->prepare("select id from object"); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + long long object_id = result.getLongLong(1); // field indices start at 1 + + statement = connection->prepare( + "update attribute_text set value=? where type=%d and object_id=%lld", + 1234, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + std::string msg("testing quote ' and accents é."); + + CPPUNIT_ASSERT(DB::Bindings(statement).bindText(1,msg.c_str(),msg.size(),NULL)); + CPPUNIT_ASSERT(connection->execute(statement)); + + statement = connection->prepare( + "select value from attribute_text as t where t.type=%d and t.object_id=%lld", + 1234, + object_id); + result = connection->perform(statement); + CPPUNIT_ASSERT_EQUAL(std::string(result.getString(1)), msg); +} + +void test_a_db_with_a_connection_with_tables::can_update_integer_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert integer attribute + statement = connection->prepare( + "insert into attribute_integer (value,type,object_id) values (%lld,%d,%lld)", + 1111, + 1235, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update integer attribute statement + statement = connection->prepare( + "update attribute_integer set value=? where type=%d and object_id=%lld", + 1235, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // bind long long value to the parameter an update the record + CPPUNIT_ASSERT(DB::Bindings(statement).bindInt64(1,2222)); + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the value from the record + DB::Statement retrieveStmt = connection->prepare( + "select value from attribute_integer as t where t.type=%d and t.object_id=%lld", + 1235, + object_id); + CPPUNIT_ASSERT(retrieveStmt.isValid()); + DB::Result result = connection->perform(retrieveStmt); + CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)2222); + + // verify that binding to a parameter before resetting the statement will fail. + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + DB::Bindings bindings(statement); + CPPUNIT_ASSERT(!bindings.bindInt(1,3333)); + DB::setLogErrorHandler(eh); + + // reset statement and bind another value to the statement + CPPUNIT_ASSERT(bindings.reset()); + CPPUNIT_ASSERT(bindings.bindInt(1,3333)); + + // perform the update statement again with the newly bound value + CPPUNIT_ASSERT(connection->execute(statement)); + + // reset the retrieve statement and perform it again to get the latest value of the integer attribute + CPPUNIT_ASSERT(retrieveStmt.reset()); + result = connection->perform(retrieveStmt); + CPPUNIT_ASSERT(result.isValid()); + CPPUNIT_ASSERT_EQUAL(result.getLongLong(1), (long long)3333); +} + +void test_a_db_with_a_connection_with_tables::can_update_blob_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert blob attribute + statement = connection->prepare( + "insert into attribute_blob (value,type,object_id) values (X'012345',%d,%lld)", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update blob attribute statement + statement = connection->prepare( + "update attribute_blob set value=? where type=%d and object_id=%lld", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // bind blob (with embedded zero!) to the parameter + const char data[] = {10,11,0,12,13,14,15,16}; + std::string msg(data,sizeof(data)); + CPPUNIT_ASSERT(DB::Bindings(statement).bindBlob(1,msg.data(),msg.size(),NULL)); + + // update the blob value of the attribute + CPPUNIT_ASSERT(connection->execute(statement)); + + // retrieve the blob value from the attribute + statement = connection->prepare( + "select value from attribute_blob as t where t.type=%d and t.object_id=%lld", + 1236, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved blob value matches the original data. + CPPUNIT_ASSERT_EQUAL(result.getFieldLength(1), sizeof(data)); + std::string msgstored((const char *)result.getBinary(1),result.getFieldLength(1)); + CPPUNIT_ASSERT_EQUAL(msg, msgstored); +} + + +void test_a_db_with_a_connection_with_tables::will_not_insert_non_existing_attribute_on_update() +{ + DB::Statement statement; + DB::Result result; + + // Insert new object + statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // Updating an attribute before it is created will succeed, but will not insert an attribute. + statement = connection->prepare( + "update attribute_boolean set value=1 where type=%d and object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the boolean value from the attribute should fail + statement = connection->prepare( + "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + result = connection->perform(statement); + CPPUNIT_ASSERT(!result.isValid()); +} + + +void test_a_db_with_a_connection_with_tables::can_update_boolean_attribute_bound_value() +{ + //SQLite doesn't have a boolean data type, use 0 (false) and 1 (true) + + DB::Statement statement; + DB::Result result; + + // Insert new object + statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert boolean attribute + statement = connection->prepare( + "insert into attribute_boolean (value,type,object_id) values (1,%d,%lld)", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update boolean attribute statement + statement = connection->prepare( + "update attribute_boolean set value=? where type=%d and object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // Bind 0 (false) to the first parameter + CPPUNIT_ASSERT(DB::Bindings(statement).bindInt(1,0)); + + // Execute the statement to update the attribute value. + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the boolean value from the attribute + statement = connection->prepare( + "select value from attribute_boolean as t where t.type=%d and t.object_id=%lld", + 1237, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value + CPPUNIT_ASSERT_EQUAL(result.getInt(1), 0); +} + + +void test_a_db_with_a_connection_with_tables::can_update_real_attribute_bound_value() +{ + // insert new object + DB::Statement statement = connection->prepare( + "insert into object default values"); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + long long object_id = connection->lastInsertRowId(); + CPPUNIT_ASSERT(object_id != 0); + + // insert real value + statement = connection->prepare( + "insert into attribute_real (value,type,object_id) values(%f,%d,%lld)", + 1.238, + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + CPPUNIT_ASSERT(connection->execute(statement)); + + // prepare update real attribute statement + statement = connection->prepare( + "update attribute_real set value=? where type=%d and object_id=%lld", + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + + // Bind 3333.3333 to the first parameter + CPPUNIT_ASSERT(DB::Bindings(statement).bindDouble(1,3333.3333)); + + // Execute the statement to update the attribute value + CPPUNIT_ASSERT(connection->execute(statement)); + + // Retrieve the double value from the attribute + statement = connection->prepare( + "select value from attribute_real as t where t.type=%d and t.object_id=%lld", + 1238, + object_id); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value. + CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001); +} + +void test_a_db_with_a_connection_with_tables::supports_transactions() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + CPPUNIT_ASSERT(!connection->rollbackTransaction()); + DB::setLogErrorHandler(eh); + + CPPUNIT_ASSERT(connection->beginTransactionRW()); + CPPUNIT_ASSERT(connection->rollbackTransaction()); + + eh = DB::setLogErrorHandler(dummy_print); + CPPUNIT_ASSERT(!connection->commitTransaction()); + DB::setLogErrorHandler(eh); + + CPPUNIT_ASSERT(connection->beginTransactionRW()); + can_update_real_attribute_bound_value(); + CPPUNIT_ASSERT(connection->commitTransaction()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_db_with_a_connection_with_tables_with_a_second_connection_open); + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::setUp() +{ + test_a_db_with_a_connection_with_tables::setUp(); + connection2 = DB::Connection::Create("testdir","TestToken"); + CPPUNIT_ASSERT(connection2 != null); + CPPUNIT_ASSERT(connection2->connect()); + connection2->setBusyTimeout(10); +} + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::tearDown() +{ + CPPUNIT_ASSERT(connection2 != null); + connection2->close(); + delete connection2; + test_a_db_with_a_connection_with_tables::tearDown(); +} + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::handles_nested_transactions() +{ + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + DB::Connection *connection1 = connection; + + CPPUNIT_ASSERT(connection1->beginTransactionRW()); + + CPPUNIT_ASSERT(connection2->beginTransactionRO()); + CPPUNIT_ASSERT(connection2->rollbackTransaction()); + CPPUNIT_ASSERT(!connection2->beginTransactionRW()); + + CPPUNIT_ASSERT(connection1->commitTransaction()); + + DB::setLogErrorHandler(eh); +} + + +void test_a_db_with_a_connection_with_tables_with_a_second_connection_open::supports_transactions_with_other_connections_open() +{ + CPPUNIT_ASSERT(connection2->beginTransactionRO()); + + supports_transactions(); + + // Retrieve the double value from the attribute + DB::Statement statement = connection2->prepare( + "select value from attribute_real as t where t.type=%d and t.object_id=%lld", + 1238, + connection->lastInsertRowId()); + CPPUNIT_ASSERT(statement.isValid()); + DB::Result result = connection2->perform(statement); + CPPUNIT_ASSERT(result.isValid()); + + // check that the retrieved value matches the original value. + CPPUNIT_ASSERT_DOUBLES_EQUAL(result.getDouble(1), 3333.3333, 0.00001); + + CPPUNIT_ASSERT(connection2->commitTransaction()); +} diff --git a/SoftHSMv2/src/lib/object_store/test/DBTests.h b/SoftHSMv2/src/lib/object_store/test/DBTests.h new file mode 100644 index 0000000..422cbce --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTests.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTests.h + + Contains lowest level test cases for the database backend implementation. + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBTESTS_H +#define _SOFTHSM_V2_DBTESTS_H + +#include <cppunit/extensions/HelperMacros.h> +#include "DB.h" + +class test_a_db : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_db); + CPPUNIT_TEST(checks_for_empty_connection_parameters); + CPPUNIT_TEST(can_be_connected_to_database); + CPPUNIT_TEST_SUITE_END(); + +public: + void checks_for_empty_connection_parameters(); + void can_be_connected_to_database(); + + void setUp(); + void tearDown(); + +protected: + DB::Connection *null; + +private: +}; + +class test_a_db_with_a_connection : public test_a_db +{ + CPPUNIT_TEST_SUITE(test_a_db_with_a_connection); + CPPUNIT_TEST(can_prepare_statements); + CPPUNIT_TEST(can_perform_statements); + CPPUNIT_TEST(maintains_correct_refcounts); + CPPUNIT_TEST(can_create_tables); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp(); + void tearDown(); + + void can_prepare_statements(); + void can_perform_statements(); + void maintains_correct_refcounts(); + void can_create_tables(); +protected: + DB::Connection *connection; + +private: +}; + +class test_a_db_with_a_connection_with_tables : public test_a_db_with_a_connection +{ + CPPUNIT_TEST_SUITE(test_a_db_with_a_connection_with_tables); + CPPUNIT_TEST(can_insert_records); + CPPUNIT_TEST(can_retrieve_records); + CPPUNIT_TEST(can_cascade_delete_objects_and_attributes); + CPPUNIT_TEST(can_update_text_attribute); + CPPUNIT_TEST(can_update_text_attribute_bound_value); + CPPUNIT_TEST(can_update_integer_attribute_bound_value); + CPPUNIT_TEST(can_update_blob_attribute_bound_value); + CPPUNIT_TEST(will_not_insert_non_existing_attribute_on_update); + CPPUNIT_TEST(can_update_boolean_attribute_bound_value); + CPPUNIT_TEST(can_update_real_attribute_bound_value); + CPPUNIT_TEST(supports_transactions); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp(); + void tearDown(); + + void can_insert_records(); + void can_retrieve_records(); + void can_cascade_delete_objects_and_attributes(); + void can_update_text_attribute(); + void can_update_text_attribute_bound_value(); + void can_update_integer_attribute_bound_value(); + void can_update_blob_attribute_bound_value(); + void will_not_insert_non_existing_attribute_on_update(); + void can_update_boolean_attribute_bound_value(); + void can_update_real_attribute_bound_value(); + void supports_transactions(); +protected: + +private: +}; + +class test_a_db_with_a_connection_with_tables_with_a_second_connection_open : public test_a_db_with_a_connection_with_tables +{ + CPPUNIT_TEST_SUITE(test_a_db_with_a_connection_with_tables_with_a_second_connection_open); + CPPUNIT_TEST(handles_nested_transactions); + CPPUNIT_TEST(supports_transactions_with_other_connections_open); + CPPUNIT_TEST_SUITE_END(); +public: + void setUp(); + void tearDown(); + + void handles_nested_transactions(); + void supports_transactions_with_other_connections_open(); +protected: + DB::Connection *connection2; + +private: +}; + +#endif // !_SOFTHSM_V2_DBTESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp new file mode 100644 index 0000000..ab0cff1 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.cpp @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTokenTests.cpp + + Contains test cases to test the database token implementation + *****************************************************************************/ +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "DBTokenTests.h" +#include "DBToken.h" +#include "DB.h" + +#include <cstdio> + +#ifndef HAVE_SQLITE3_H +#error expected sqlite3 to be available +#endif + +CPPUNIT_TEST_SUITE_REGISTRATION(test_a_dbtoken); + +static int dummy_print(const char *, va_list ) +{ + return 0; +} + +void test_a_dbtoken::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); +} + +void test_a_dbtoken::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void test_a_dbtoken::should_be_creatable() +{ + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + + ObjectStoreToken* newToken = new DBToken("testdir", "newToken", label, serial); + + CPPUNIT_ASSERT(newToken != NULL); + + CPPUNIT_ASSERT(newToken->isValid()); + + delete newToken; +} + +void test_a_dbtoken::should_support_pin_setting_getting() +{ + // Create a new token + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + + ObjectStoreToken* newToken = new DBToken("testdir", "newToken", label, serial); + + CPPUNIT_ASSERT(newToken != NULL); + + CPPUNIT_ASSERT(newToken->isValid()); + + // Check the flags + CK_ULONG flags; + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)( CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED)); + + // Set the SO PIN + ByteString soPIN = "3132333435363738"; // 12345678 + + CPPUNIT_ASSERT(newToken->setSOPIN(soPIN)); + + // Set the user PIN + ByteString userPIN = "31323334"; // 1234 + + CPPUNIT_ASSERT(newToken->setUserPIN(userPIN)); + + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + delete newToken; + + // Now reopen the newly created token + DBToken reopenedToken("testdir","newToken"); + + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Retrieve the flags, user PIN and so PIN + ByteString retrievedSOPIN, retrievedUserPIN; + + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); +} + +void test_a_dbtoken::should_allow_object_enumeration() +{ + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + ByteString soPIN = "31323334"; // 1234 + ByteString userPIN = "30303030"; // 0000 + ByteString id[3] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB" }; + + { + // Instantiate a new token + ObjectStoreToken* newToken = new DBToken("testdir", "existingToken", label, serial); + CPPUNIT_ASSERT(newToken != NULL); + CPPUNIT_ASSERT(newToken->isValid()); + CPPUNIT_ASSERT(newToken->setSOPIN(soPIN)); + CPPUNIT_ASSERT(newToken->setUserPIN(userPIN)); + + // Test IDs + OSAttribute idAtt[3] = { id[0], id[1], id[2] }; + + // Create 3 objects on the token + OSObject* obj1 = newToken->createObject(); + CPPUNIT_ASSERT(obj1 != NULL); + OSObject* obj2 = newToken->createObject(); + CPPUNIT_ASSERT(obj2 != NULL); + OSObject* obj3 = newToken->createObject(); + CPPUNIT_ASSERT(obj3 != NULL); + + // Now set the IDs of the 3 objects + obj1->startTransaction(OSObject::ReadWrite); + CPPUNIT_ASSERT(obj1->setAttribute(CKA_ID, idAtt[0])); + obj1->commitTransaction(); + + obj2->startTransaction(OSObject::ReadWrite); + CPPUNIT_ASSERT(obj2->setAttribute(CKA_ID, idAtt[1])); + obj2->commitTransaction(); + + obj3->startTransaction(OSObject::ReadWrite); + CPPUNIT_ASSERT(obj3->setAttribute(CKA_ID, idAtt[2])); + obj3->commitTransaction(); + + delete newToken; + } + + // Now open the token + DBToken existingToken("testdir","existingToken"); + + CPPUNIT_ASSERT(existingToken.isValid()); + + // Retrieve SO PIN, user PIN, label, serial number and flags + ByteString retrievedSOPIN, retrievedUserPIN, retrievedLabel, retrievedSerial; + CK_ULONG flags; + + CPPUNIT_ASSERT(existingToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(existingToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(existingToken.getTokenLabel(retrievedLabel)); + CPPUNIT_ASSERT(existingToken.getTokenSerial(retrievedSerial)); + CPPUNIT_ASSERT(existingToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT(retrievedLabel == label); + CPPUNIT_ASSERT(retrievedSerial == serial); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + // Check that the token contains 3 objects + CPPUNIT_ASSERT_EQUAL(existingToken.getObjects().size(), (size_t)3); + + // Check that all the tokens are presented + bool present[3] = { false, false, false }; + std::set<OSObject*> objects = existingToken.getObjects(); + + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present[0] = true; + } + else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1]) + { + present[1] = true; + } + else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present[2] = true; + } + } + + CPPUNIT_ASSERT(present[0]); + CPPUNIT_ASSERT(present[1]); + CPPUNIT_ASSERT(present[2]); +} + +void test_a_dbtoken::should_fail_to_open_nonexistant_tokens() +{ + DBToken doesntExist("testdir","doesntExist"); + + CPPUNIT_ASSERT(!doesntExist.isValid()); +} + +void test_a_dbtoken::support_create_delete_objects() +{ + // Test IDs + ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" }; + OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] }; + ByteString label = "AABBCCDDEEFF"; + ByteString serial = "1234567890"; + + // Instantiate a new token + ObjectStoreToken* testToken = new DBToken("testdir", "testToken", label, serial); + CPPUNIT_ASSERT(testToken != NULL); + CPPUNIT_ASSERT(testToken->isValid()); + + // Open the same token + DBToken sameToken("testdir","testToken"); + CPPUNIT_ASSERT(sameToken.isValid()); + + // Create 3 objects on the token + OSObject* obj1 = testToken->createObject(); + CPPUNIT_ASSERT(obj1 != NULL); + OSObject* obj2 = testToken->createObject(); + CPPUNIT_ASSERT(obj2 != NULL); + OSObject* obj3 = testToken->createObject(); + CPPUNIT_ASSERT(obj3 != NULL); + + // Now set the IDs of the 3 objects + obj1->setAttribute(CKA_ID, idAtt[0]); + obj2->setAttribute(CKA_ID, idAtt[1]); + obj3->setAttribute(CKA_ID, idAtt[2]); + + // Check that the token contains 3 objects + CPPUNIT_ASSERT_EQUAL(testToken->getObjects().size(), (size_t)3); + + // Check that all three objects are distinct and present + std::set<OSObject*> objects = testToken->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + for (int j = 0; j < 3; j++) + { + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j]) + { + present1[j] = true; + } + } + } + + for (int j = 0; j < 3; j++) + { + CPPUNIT_ASSERT(present1[j]); + } + + // Now check that the same objects are present in the other instance of the same token + std::set<OSObject*> otherObjects = sameToken.getObjects(); + CPPUNIT_ASSERT_EQUAL(otherObjects.size(), (size_t)3); + + bool present2[3] = { false, false, false }; + + for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + for (int j = 0; j < 3; j++) + { + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j]) + { + present2[j] = true; + } + } + } + + for (int j = 0; j < 3; j++) + { + CPPUNIT_ASSERT(present2[j]); + } + + // Now delete the second object + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1]) + { + CPPUNIT_ASSERT(testToken->deleteObject(*i)); + break; + } + } + + // Verify that it was indeed removed + CPPUNIT_ASSERT_EQUAL(testToken->getObjects().size(),(size_t)2); + + objects = testToken->getObjects(); + bool present3[2] = { false, false }; + + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present3[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present3[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present3[j]); + } + + // Now check the other instance + CPPUNIT_ASSERT_EQUAL(sameToken.getObjects().size(), (size_t)2); + + otherObjects = sameToken.getObjects(); + bool present4[2] = { false, false }; + + for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present4[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present4[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present4[j]); + } + + + // Release the test token + delete testToken; +} + +void test_a_dbtoken::support_clearing_a_token() +{ + // Create a new token + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + + ObjectStoreToken* newToken = new DBToken("testdir", "newToken", label, serial); + + CPPUNIT_ASSERT(newToken != NULL); + CPPUNIT_ASSERT(newToken->isValid()); + + // Check the flags + CK_ULONG flags; + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED)); + + // Set the SO PIN + ByteString soPIN = "3132333435363738"; // 12345678 + + CPPUNIT_ASSERT(newToken->setSOPIN(soPIN)); + + // Set the user PIN + ByteString userPIN = "31323334"; // 1234 + + CPPUNIT_ASSERT(newToken->setUserPIN(userPIN)); + + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + CPPUNIT_ASSERT(newToken->createObject() != NULL); + + delete newToken; + +#if 1 + // Reopen the newly created token and keep a reference around. + DBToken referencingToken("testdir", "newToken"); + CPPUNIT_ASSERT(referencingToken.isValid()); +#endif + // Now reopen the newly created token + DBToken reopenedToken("testdir","newToken"); + + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Retrieve the flags, user PIN and so PIN + ByteString retrievedSOPIN, retrievedUserPIN; + + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + // Now reset the token + CPPUNIT_ASSERT(reopenedToken.resetToken(label)); + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(!reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT_EQUAL(flags, (CK_ULONG)(CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED)); + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Now clear the token + CPPUNIT_ASSERT(reopenedToken.clearToken()); + CPPUNIT_ASSERT(!reopenedToken.isValid()); + + DB::LogErrorHandler eh = DB::setLogErrorHandler(dummy_print); + + // Try to open it once more and make sure it has been deleted. + DBToken clearedToken("testdir","newToken"); + CPPUNIT_ASSERT(!clearedToken.isValid()); + +#if 1 + // Verify that it is no longer possible to access the database... + CPPUNIT_ASSERT(!referencingToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + + std::set<OSObject *> objects = referencingToken.getObjects(); + CPPUNIT_ASSERT_EQUAL(objects.size(), (size_t)0); + + CPPUNIT_ASSERT(!referencingToken.isValid()); +#endif + + DB::setLogErrorHandler(eh); +} diff --git a/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h new file mode 100644 index 0000000..de25195 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DBTokenTests.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DBTokenTests.h + + Contains test cases to test the database token implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DBTOKENTESTS_H +#define _SOFTHSM_V2_DBTOKENTESTS_H + +#include <cppunit/extensions/HelperMacros.h> +#include "DBToken.h" + +class test_a_dbtoken : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(test_a_dbtoken); + CPPUNIT_TEST(should_be_creatable); + CPPUNIT_TEST(should_support_pin_setting_getting); + CPPUNIT_TEST(should_allow_object_enumeration); + CPPUNIT_TEST(should_fail_to_open_nonexistant_tokens); + CPPUNIT_TEST(support_create_delete_objects); + CPPUNIT_TEST(support_clearing_a_token); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void should_be_creatable(); + void should_support_pin_setting_getting(); + void should_allow_object_enumeration(); + void should_fail_to_open_nonexistant_tokens(); + void support_create_delete_objects(); + void support_clearing_a_token(); + +protected: + +private: +}; + +#endif // !_SOFTHSM_V2_DBTOKENTESTS_H diff --git a/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp new file mode 100644 index 0000000..2b56a5a --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DirectoryTests.cpp + + Contains test cases to test the directory implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "DirectoryTests.h" +#include "Directory.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(DirectoryTests); + +void DirectoryTests::setUp() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("mkdir testdir")); + CPPUNIT_ASSERT(!system("mkdir testdir/anotherdir")); + CPPUNIT_ASSERT(!system("mkdir testdir/anotherdir2")); + CPPUNIT_ASSERT(!system("mkdir testdir/anotherdir3")); + CPPUNIT_ASSERT(!system("echo someStuff > testdir/afile")); + CPPUNIT_ASSERT(!system("echo someOtherStuff > testdir/anotherFile")); + CPPUNIT_ASSERT(!system("echo justStuff > testdir/justaFile")); +#else + CPPUNIT_ASSERT(!system("mkdir testdir")); + CPPUNIT_ASSERT(!system("mkdir testdir\\anotherdir")); + CPPUNIT_ASSERT(!system("mkdir testdir\\anotherdir2")); + CPPUNIT_ASSERT(!system("mkdir testdir\\anotherdir3")); + CPPUNIT_ASSERT(!system("echo someStuff > testdir\\afile")); + CPPUNIT_ASSERT(!system("echo someOtherStuff > testdir\\anotherFile")); + CPPUNIT_ASSERT(!system("echo justStuff > testdir\\justaFile")); +#endif +} + +void DirectoryTests::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void DirectoryTests::testDirectory() +{ +#ifndef _WIN32 + Directory testdir("./testdir"); +#else + Directory testdir(".\\testdir"); +#endif + + CPPUNIT_ASSERT(testdir.isValid()); + + std::vector<std::string> files = testdir.getFiles(); + std::vector<std::string> subDirs = testdir.getSubDirs(); + + CPPUNIT_ASSERT(files.size() == 3); + CPPUNIT_ASSERT(subDirs.size() == 3); + + CPPUNIT_ASSERT(testdir.refresh()); + + CPPUNIT_ASSERT(files.size() == 3); + CPPUNIT_ASSERT(subDirs.size() == 3); + + bool fileSeen[3] = { false, false, false }; + + for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); i++) + { + if (!i->compare("afile")) + { + fileSeen[0] = true; + } + else if (!i->compare("anotherFile")) + { + fileSeen[1] = true; + } + else if (!i->compare("justaFile")) + { + fileSeen[2] = true; + } + else + { + CPPUNIT_ASSERT(false); + } + } + + CPPUNIT_ASSERT(fileSeen[0] && fileSeen[1] && fileSeen[2]); + + bool dirSeen[3] = { false, false, false }; + + for (std::vector<std::string>::iterator i = subDirs.begin(); i != subDirs.end(); i++) + { + if (!i->compare("anotherdir")) + { + dirSeen[0] = true; + } + else if (!i->compare("anotherdir2")) + { + dirSeen[1] = true; + } + else if (!i->compare("anotherdir3")) + { + dirSeen[2] = true; + } + else + { + CPPUNIT_ASSERT(false); + } + } + + CPPUNIT_ASSERT(dirSeen[0] && dirSeen[1] && dirSeen[2]); + + // Create a directory + CPPUNIT_ASSERT(testdir.mkdir("newDir")); + + subDirs = testdir.getSubDirs(); + + bool dirSeen2[4] = { false, false, false, false }; + + for (std::vector<std::string>::iterator i = subDirs.begin(); i != subDirs.end(); i++) + { + if (!i->compare("anotherdir")) + { + dirSeen2[0] = true; + } + else if (!i->compare("anotherdir2")) + { + dirSeen2[1] = true; + } + else if (!i->compare("anotherdir3")) + { + dirSeen2[2] = true; + } + else if (!i->compare("newDir")) + { + dirSeen2[3] = true; + } + else + { + CPPUNIT_ASSERT(false); + } + } + + CPPUNIT_ASSERT(dirSeen2[0] && dirSeen2[1] && dirSeen2[2] && dirSeen2[3]); + + // Remove a directory + CPPUNIT_ASSERT(testdir.rmdir("anotherdir2", true)); + + subDirs = testdir.getSubDirs(); + + bool dirSeen3[3] = { false, false, false }; + + for (std::vector<std::string>::iterator i = subDirs.begin(); i != subDirs.end(); i++) + { + if (!i->compare("anotherdir")) + { + dirSeen3[0] = true; + } + else if (!i->compare("newDir")) + { + dirSeen3[1] = true; + } + else if (!i->compare("anotherdir3")) + { + dirSeen3[2] = true; + } + else + { + CPPUNIT_ASSERT(false); + } + } + + CPPUNIT_ASSERT(dirSeen3[0] && dirSeen3[1] && dirSeen3[2]); + + // Remove a file + CPPUNIT_ASSERT(testdir.remove("anotherFile")); + + files = testdir.getFiles(); + + bool fileSeen2[2] = { false, false }; + + for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); i++) + { + if (!i->compare("afile")) + { + fileSeen2[0] = true; + } + else if (!i->compare("justaFile")) + { + fileSeen2[1] = true; + } + else + { + CPPUNIT_ASSERT(false); + } + } + + CPPUNIT_ASSERT(fileSeen2[0] && fileSeen2[1]); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h new file mode 100644 index 0000000..777f1a8 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/DirectoryTests.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + DirectoryTests.h + + Contains test cases to test the Directory implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_DIRECTORYTESTS_H +#define _SOFTHSM_V2_DIRECTORYTESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class DirectoryTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(DirectoryTests); + CPPUNIT_TEST(testDirectory); + CPPUNIT_TEST_SUITE_END(); + +public: + void testDirectory(); + + void setUp(); + void tearDown(); + +private: +}; + +#endif // !_SOFTHSM_V2_DIRECTORYTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/FileTests.cpp b/SoftHSMv2/src/lib/object_store/test/FileTests.cpp new file mode 100644 index 0000000..9ac0979 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/FileTests.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + FileTests.cpp + + Contains test cases to test the file implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "FileTests.h" +#include "File.h" +#include "Directory.h" +#include "CryptoFactory.h" +#include "RNG.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(FileTests); + +// FIXME: all pathnames in this file are *NIX/BSD specific + +void FileTests::setUp() +{ +#ifndef _WIN32 + int rv = system("rm -rf testdir"); +#else + int rv = system("rmdir /s /q testdir 2> nul"); +#endif + (void) rv; + + CPPUNIT_ASSERT(!system("mkdir testdir")); +} + +void FileTests::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void FileTests::testExistNotExist() +{ + // Test pre-condition + CPPUNIT_ASSERT(!exists("nonExistentFile")); + + // Attempt to open a file known not to exist +#ifndef _WIN32 + File doesntExist("testdir/nonExistentFile"); +#else + File doesntExist("testdir\\nonExistentFile"); +#endif + + CPPUNIT_ASSERT(!doesntExist.isValid()); + + // Attempt to open a file known to exist +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("echo someStuff > testdir/existingFile")); +#else + CPPUNIT_ASSERT(!system("echo someStuff > testdir\\existingFile")); +#endif + CPPUNIT_ASSERT(exists("existingFile")); + +#ifndef _WIN32 + File exists("testdir/existingFile"); +#else + File exists("testdir\\existingFile"); +#endif + + CPPUNIT_ASSERT(exists.isValid()); +} + +void FileTests::testCreateNotCreate() +{ + // Test pre-condition + CPPUNIT_ASSERT(!exists("nonExistentFile")); + CPPUNIT_ASSERT(!exists("nonExistentFile2")); + + // Attempt to open a file known not to exist +#ifndef _WIN32 + File doesntExist("testdir/nonExistentFile", true, true, false); +#else + File doesntExist("testdir\\nonExistentFile", true, true, false); +#endif + + CPPUNIT_ASSERT(!doesntExist.isValid()); + CPPUNIT_ASSERT(!exists("nonExistentFile")); + + // Attempt to open a file known not to exist in create mode +#ifndef _WIN32 + File willBeCreated("testdir/nonExistentFile2", true, true, true); +#else + File willBeCreated("testdir\\nonExistentFile2", true, true, true); +#endif + + CPPUNIT_ASSERT(willBeCreated.isValid()); + CPPUNIT_ASSERT(exists("nonExistentFile2")); +} + +void FileTests::testLockUnlock() +{ + // Create pre-condition +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("echo someStuff > testdir/existingFile")); +#else + CPPUNIT_ASSERT(!system("echo someStuff > testdir\\existingFile")); +#endif + CPPUNIT_ASSERT(exists("existingFile")); + +#ifndef _WIN32 + File file1("testdir/existingFile"); + File file2("testdir/existingFile"); +#else + File file1("testdir\\existingFile"); + File file2("testdir\\existingFile"); +#endif + + CPPUNIT_ASSERT(file1.lock(false)); + CPPUNIT_ASSERT(!file1.lock(false)); + CPPUNIT_ASSERT(file2.lock(false)); + CPPUNIT_ASSERT(file2.unlock()); + CPPUNIT_ASSERT(file1.unlock()); + CPPUNIT_ASSERT(file1.lock()); + CPPUNIT_ASSERT(file2.lock()); + CPPUNIT_ASSERT(file2.unlock()); + CPPUNIT_ASSERT(file1.unlock()); +} + +void FileTests::testWriteRead() +{ + // Generate some test data + RNG* rng = CryptoFactory::i()->getRNG(); + + ByteString testData1; + + CPPUNIT_ASSERT(rng->generateRandom(testData1, 187)); + + // More test data + std::string testString = "This is a test of the File class"; + std::set<CK_MECHANISM_TYPE> testSet; + testSet.insert(CKM_RSA_PKCS); + testSet.insert(CKM_SHA256_RSA_PKCS); + + // Create a file for writing + { +#ifndef _WIN32 + File newFile("testdir/newFile", false, true); +#else + File newFile("testdir\\newFile", false, true); +#endif + + CPPUNIT_ASSERT(newFile.isValid()); + + // Write two booleans into the file + CPPUNIT_ASSERT(newFile.writeBool(true)); + CPPUNIT_ASSERT(newFile.writeBool(false)); + + // Write an ulong into the file + CPPUNIT_ASSERT(newFile.writeULong(0x12345678)); + + // Write a ByteString into the file + CPPUNIT_ASSERT(newFile.writeByteString(testData1)); + + // Write a string into the file + CPPUNIT_ASSERT(newFile.writeString(testString)); + + // Write a set into the file + CPPUNIT_ASSERT(newFile.writeMechanismTypeSet(testSet)); + } + + CPPUNIT_ASSERT(exists("newFile")); + + // Read the created file back + { +#ifndef _WIN32 + File newFile("testdir/newFile"); +#else + File newFile("testdir\\newFile"); +#endif + + CPPUNIT_ASSERT(newFile.isValid()); + + // Read back the two booleans + bool b1, b2; + + CPPUNIT_ASSERT(newFile.readBool(b1) && newFile.readBool(b2)); + CPPUNIT_ASSERT(b1 && !b2); + + // Read back the ulong + unsigned long ulongValue; + + CPPUNIT_ASSERT(newFile.readULong(ulongValue)); + CPPUNIT_ASSERT(ulongValue == 0x12345678); + + // Read back the byte string + ByteString bsValue; + + CPPUNIT_ASSERT(newFile.readByteString(bsValue)); + CPPUNIT_ASSERT(bsValue == testData1); + + // Read back the string value + std::string stringVal; + + CPPUNIT_ASSERT(newFile.readString(stringVal)); + CPPUNIT_ASSERT(!testString.compare(stringVal)); + + // Read back the set value + std::set<CK_MECHANISM_TYPE> setVal; + + CPPUNIT_ASSERT(newFile.readMechanismTypeSet(setVal)); + CPPUNIT_ASSERT(setVal == testSet); + + // Check for EOF + CPPUNIT_ASSERT(!newFile.readBool(b1)); + CPPUNIT_ASSERT(newFile.isEOF()); + } +} + +void FileTests::testSeek() +{ + ByteString t1 = "112233445566778899"; // 9 long + ByteString t2 = "AABBCCDDEEFFAABBCCDDEEFF"; // 12 long + + { + // Create the test file +#ifndef _WIN32 + File testFile("testdir/testFile", false, true, true); +#else + File testFile("testdir\\testFile", false, true, true); +#endif + + CPPUNIT_ASSERT(testFile.isValid()); + + // Write the test data to the test file + CPPUNIT_ASSERT(testFile.writeByteString(t1) && testFile.writeByteString(t2)); + } + + // Open the test file for reading +#ifndef _WIN32 + File testFile("testdir/testFile"); +#else + File testFile("testdir\\testFile"); +#endif + + CPPUNIT_ASSERT(testFile.isValid()); + + // First, read back the test data + ByteString tr1, tr2; + + CPPUNIT_ASSERT(testFile.readByteString(tr1) && testFile.readByteString(tr2)); + CPPUNIT_ASSERT(tr1 == t1); + CPPUNIT_ASSERT(tr2 == t2); + + // Seek to the length field of the second byte string + CPPUNIT_ASSERT(testFile.seek(8+9)); + + // Read back the size as an ulong value + unsigned long value; + unsigned long expectedValue = (unsigned long)0x1122334455667788ULL; + + CPPUNIT_ASSERT(testFile.readULong(value)); + CPPUNIT_ASSERT(value == 12); + + // Seek to the start of the first byte string's data + CPPUNIT_ASSERT(testFile.seek(8)); + + // Read back the ulong value stored there + CPPUNIT_ASSERT(testFile.readULong(value)); + + CPPUNIT_ASSERT(value == expectedValue); + + // Seek to the start of second byte string + CPPUNIT_ASSERT(testFile.seek(8+9)); + + // Read it + ByteString trr2; + + CPPUNIT_ASSERT(testFile.readByteString(trr2)); + CPPUNIT_ASSERT(trr2 == t2); + + // Rewind the file + CPPUNIT_ASSERT(testFile.rewind()); + + // Read back both byte strings + ByteString trrr1, trrr2; + + CPPUNIT_ASSERT(testFile.readByteString(trrr1) && testFile.readByteString(trrr2)); + CPPUNIT_ASSERT(trrr1 == t1); + CPPUNIT_ASSERT(trrr2 == t2); +} + +bool FileTests::exists(std::string name) +{ +#ifndef _WIN32 + Directory dir("./testdir"); +#else + Directory dir(".\\testdir"); +#endif + + + CPPUNIT_ASSERT(dir.isValid()); + + std::vector<std::string> files = dir.getFiles(); + + for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); i++) + { + if (!i->compare(name)) + { + return true; + } + } + + return false; +} + diff --git a/SoftHSMv2/src/lib/object_store/test/FileTests.h b/SoftHSMv2/src/lib/object_store/test/FileTests.h new file mode 100644 index 0000000..0b87f26 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/FileTests.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + FileTests.h + + Contains test cases to test the File implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_FILETESTS_H +#define _SOFTHSM_V2_FILETESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class FileTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(FileTests); + CPPUNIT_TEST(testExistNotExist); + CPPUNIT_TEST(testCreateNotCreate); + CPPUNIT_TEST(testLockUnlock); + CPPUNIT_TEST(testWriteRead); + CPPUNIT_TEST(testSeek); + CPPUNIT_TEST_SUITE_END(); + +public: + void testExistNotExist(); + void testCreateNotCreate(); + void testLockUnlock(); + void testWriteRead(); + void testSeek(); + + void setUp(); + void tearDown(); + +private: + bool exists(std::string path); +}; + +#endif // !_SOFTHSM_V2_FILETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/Makefile.am b/SoftHSMv2/src/lib/object_store/test/Makefile.am new file mode 100644 index 0000000..71de7dd --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/Makefile.am @@ -0,0 +1,39 @@ +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in + +AM_CPPFLAGS = -I$(srcdir)/.. \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../../common \ + -I$(srcdir)/../../crypto \ + -I$(srcdir)/../../data_mgr \ + -I$(srcdir)/../../pkcs11 \ + -I$(srcdir)/../../session_mgr \ + -I$(srcdir)/../../slot_mgr \ + @CPPUNIT_CFLAGS@ \ + @CRYPTO_INCLUDES@ + +check_PROGRAMS = objstoretest + +objstoretest_SOURCES = objstoretest.cpp \ + DirectoryTests.cpp \ + UUIDTests.cpp \ + FileTests.cpp \ + ObjectFileTests.cpp \ + OSTokenTests.cpp \ + ObjectStoreTests.cpp \ + SessionObjectTests.cpp \ + SessionObjectStoreTests.cpp + +if BUILD_OBJECTSTORE_BACKEND_DB +objstoretest_SOURCES += DBTests.cpp \ + DBObjectTests.cpp \ + DBTokenTests.cpp \ + DBObjectStoreTests.cpp +endif + +objstoretest_LDADD = ../../libsofthsm_convarch.la + +objstoretest_LDFLAGS = @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install -pthread + +TESTS = objstoretest + +EXTRA_DIST = $(srcdir)/*.h diff --git a/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp new file mode 100644 index 0000000..5afd583 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.cpp @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + OSTokenTests.cpp + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "OSTokenTests.h" +#include "OSToken.h" +#include "ObjectFile.h" +#include "File.h" +#include "Directory.h" +#include "OSAttribute.h" +#include "OSAttributes.h" +#include "cryptoki.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(OSTokenTests); + +// FIXME: all pathnames in this file are *NIX/BSD specific + +void OSTokenTests::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); +} + +void OSTokenTests::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void OSTokenTests::testNewToken() +{ + // Create a new token + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + +#ifndef _WIN32 + OSToken* newToken = OSToken::createToken("./testdir", "newToken", label, serial); +#else + OSToken* newToken = OSToken::createToken(".\\testdir", "newToken", label, serial); +#endif + + CPPUNIT_ASSERT(newToken != NULL); + + // Check the flags + CK_ULONG flags; + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED)); + + // Set the SO PIN + ByteString soPIN = "3132333435363738"; // 12345678 + + CPPUNIT_ASSERT(newToken->setSOPIN(soPIN)); + + // Set the user PIN + ByteString userPIN = "31323334"; // 1234 + + CPPUNIT_ASSERT(newToken->setUserPIN(userPIN)); + + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + delete newToken; + + // Now reopen the newly created token +#ifndef _WIN32 + OSToken reopenedToken("./testdir/newToken"); +#else + OSToken reopenedToken(".\\testdir\\newToken"); +#endif + + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Retrieve the flags, user PIN and so PIN + ByteString retrievedSOPIN, retrievedUserPIN; + + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); +} + +void OSTokenTests::testExistingToken() +{ + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + ByteString soPIN = "31323334"; // 1234 + ByteString userPIN = "30303030"; // 0000 + ByteString id1 = "ABCDEF"; + ByteString id2 = "FEDCBA"; + ByteString id3 = "AABBCC"; + + { + // Create the token dir +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("mkdir testdir/existingToken")); +#else + CPPUNIT_ASSERT(!system("mkdir testdir\\existingToken")); +#endif + + // Create the token object +#ifndef _WIN32 + ObjectFile tokenObject(NULL, "./testdir/existingToken/token.object", "./testdir/existingToken/token.lock", true); +#else + ObjectFile tokenObject(NULL, ".\\testdir\\existingToken\\token.object", ".\\testdir\\existingToken\\token.lock", true); +#endif + + OSAttribute labelAtt(label); + CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_TOKENLABEL, labelAtt)); + OSAttribute serialAtt(serial); + CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_TOKENSERIAL, serialAtt)); + OSAttribute soPINAtt(soPIN); + CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_SOPIN, soPINAtt)); + OSAttribute userPINAtt(userPIN); + CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_USERPIN, userPINAtt)); + CK_ULONG flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED; + OSAttribute flagsAtt(flags); + CPPUNIT_ASSERT(tokenObject.setAttribute(CKA_OS_TOKENFLAGS, flagsAtt)); + + // Create 3 objects +#ifndef _WIN32 + ObjectFile obj1(NULL, "./testdir/existingToken/1.object", "./testdir/existingToken/1.lock", true); + ObjectFile obj2(NULL, "./testdir/existingToken/2.object", "./testdir/existingToken/2.lock", true); + ObjectFile obj3(NULL, "./testdir/existingToken/3.object", "./testdir/existingToken/3.lock", true); +#else + ObjectFile obj1(NULL, ".\\testdir\\existingToken\\1.object", ".\\testdir\\existingToken\\1.lock", true); + ObjectFile obj2(NULL, ".\\testdir\\existingToken\\2.object", ".\\testdir\\existingToken\\2.lock", true); + ObjectFile obj3(NULL, ".\\testdir\\existingToken\\3.object", ".\\testdir\\existingToken\\3.lock", true); +#endif + + OSAttribute id1Att(id1); + OSAttribute id2Att(id2); + OSAttribute id3Att(id3); + + CPPUNIT_ASSERT(obj1.setAttribute(CKA_ID, id1)); + CPPUNIT_ASSERT(obj2.setAttribute(CKA_ID, id2)); + CPPUNIT_ASSERT(obj3.setAttribute(CKA_ID, id3)); + } + + // Now open the token +#ifndef _WIN32 + OSToken existingToken("./testdir/existingToken"); +#else + OSToken existingToken(".\\testdir\\existingToken"); +#endif + + + CPPUNIT_ASSERT(existingToken.isValid()); + + // Retrieve SO PIN, user PIN, label, serial number and flags + ByteString retrievedSOPIN, retrievedUserPIN, retrievedLabel, retrievedSerial; + CK_ULONG flags; + + CPPUNIT_ASSERT(existingToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(existingToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(existingToken.getTokenLabel(retrievedLabel)); + CPPUNIT_ASSERT(existingToken.getTokenSerial(retrievedSerial)); + CPPUNIT_ASSERT(existingToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT(retrievedLabel == label); + CPPUNIT_ASSERT(retrievedSerial == serial); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + // Check that the token contains 3 objects + CPPUNIT_ASSERT(existingToken.getObjects().size() == 3); + + // Check that all the tokens are presented + bool present[3] = { false, false, false }; + std::set<OSObject*> objects = existingToken.getObjects(); + + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id1) + { + present[0] = true; + } + else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id2) + { + present[1] = true; + } + else if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id3) + { + present[2] = true; + } + } + + CPPUNIT_ASSERT(present[0] == true); + CPPUNIT_ASSERT(present[1] == true); + CPPUNIT_ASSERT(present[2] == true); +} + +void OSTokenTests::testNonExistentToken() +{ +#ifndef _WIN32 + OSToken doesntExist("./testdir/doesntExist"); +#else + OSToken doesntExist(".\\testdir\\doesntExist"); +#endif + + CPPUNIT_ASSERT(!doesntExist.isValid()); +} + +void OSTokenTests::testCreateDeleteObjects() +{ + // Test IDs + ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" }; + OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] }; + ByteString label = "AABBCCDDEEFF"; + ByteString serial = "1234567890"; + + // Instantiate a new token +#ifndef _WIN32 + OSToken* testToken = OSToken::createToken("./testdir", "testToken", label, serial); +#else + OSToken* testToken = OSToken::createToken(".\\testdir", "testToken", label, serial); +#endif + + CPPUNIT_ASSERT(testToken != NULL); + CPPUNIT_ASSERT(testToken->isValid()); + + // Open the same token +#ifndef _WIN32 + OSToken sameToken("./testdir/testToken"); +#else + OSToken sameToken(".\\testdir\\testToken"); +#endif + + CPPUNIT_ASSERT(sameToken.isValid()); + + // Create 3 objects on the token + OSObject* obj1 = testToken->createObject(); + CPPUNIT_ASSERT(obj1 != NULL); + OSObject* obj2 = testToken->createObject(); + CPPUNIT_ASSERT(obj2 != NULL); + OSObject* obj3 = testToken->createObject(); + CPPUNIT_ASSERT(obj3 != NULL); + + // Now set the IDs of the 3 objects + obj1->setAttribute(CKA_ID, idAtt[0]); + obj2->setAttribute(CKA_ID, idAtt[1]); + obj3->setAttribute(CKA_ID, idAtt[2]); + + // Check that the token contains 3 objects + CPPUNIT_ASSERT(testToken->getObjects().size() == 3); + + // Check that all three objects are distinct and present + std::set<OSObject*> objects = testToken->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + for (int j = 0; j < 3; j++) + { + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j]) + { + present1[j] = true; + } + } + } + + for (int j = 0; j < 3; j++) + { + CPPUNIT_ASSERT(present1[j] == true); + } + + // Now check that the same objects are present in the other instance of the same token + std::set<OSObject*> otherObjects = sameToken.getObjects(); + CPPUNIT_ASSERT(otherObjects.size() == 3); + + bool present2[3] = { false, false, false }; + + for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + for (int j = 0; j < 3; j++) + { + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j]) + { + present2[j] = true; + } + } + } + + for (int j = 0; j < 3; j++) + { + CPPUNIT_ASSERT(present2[j] == true); + } + + // Now delete the second object + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1]) + { + CPPUNIT_ASSERT(testToken->deleteObject(*i)); + break; + } + } + + // Verify that it was indeed removed + CPPUNIT_ASSERT(testToken->getObjects().size() == 2); + + objects = testToken->getObjects(); + bool present3[2] = { false, false }; + + for (std::set<OSObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present3[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present3[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present3[j] == true); + } + + // Now check the other instance + CPPUNIT_ASSERT(sameToken.getObjects().size() == 2); + + otherObjects = sameToken.getObjects(); + bool present4[2] = { false, false }; + + for (std::set<OSObject*>::iterator i = otherObjects.begin(); i != otherObjects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present4[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present4[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present4[j] == true); + } + + + // Release the test token + delete testToken; +} + +void OSTokenTests::testClearToken() +{ + // Create a new token + ByteString label = "40414243"; // ABCD + ByteString serial = "0102030405060708"; + +#ifndef _WIN32 + OSToken* newToken = OSToken::createToken("./testdir", "newToken", label, serial); +#else + OSToken* newToken = OSToken::createToken(".\\testdir", "newToken", label, serial); +#endif + + CPPUNIT_ASSERT(newToken != NULL); + + // Check the flags + CK_ULONG flags; + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_SO_PIN_LOCKED | CKF_SO_PIN_TO_BE_CHANGED)); + + // Set the SO PIN + ByteString soPIN = "3132333435363738"; // 12345678 + + CPPUNIT_ASSERT(newToken->setSOPIN(soPIN)); + + // Set the user PIN + ByteString userPIN = "31323334"; // 1234 + + CPPUNIT_ASSERT(newToken->setUserPIN(userPIN)); + + CPPUNIT_ASSERT(newToken->getTokenFlags(flags)); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + delete newToken; + + // Now reopen the newly created token +#ifndef _WIN32 + OSToken reopenedToken("./testdir/newToken"); +#else + OSToken reopenedToken(".\\testdir\\newToken"); +#endif + + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Retrieve the flags, user PIN and so PIN + ByteString retrievedSOPIN, retrievedUserPIN; + + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(retrievedUserPIN == userPIN); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED)); + + // Now reset the token + CPPUNIT_ASSERT(reopenedToken.resetToken(label)); + CPPUNIT_ASSERT(reopenedToken.getSOPIN(retrievedSOPIN)); + CPPUNIT_ASSERT(!reopenedToken.getUserPIN(retrievedUserPIN)); + CPPUNIT_ASSERT(reopenedToken.getTokenFlags(flags)); + CPPUNIT_ASSERT(retrievedSOPIN == soPIN); + CPPUNIT_ASSERT(flags == (CKF_RNG | CKF_LOGIN_REQUIRED | CKF_RESTORE_KEY_NOT_NEEDED | CKF_TOKEN_INITIALIZED)); + CPPUNIT_ASSERT(reopenedToken.isValid()); + + // Now clear the token + CPPUNIT_ASSERT(reopenedToken.clearToken()); + CPPUNIT_ASSERT(!reopenedToken.isValid()); + + // Try to open it once more +#ifndef _WIN32 + OSToken clearedToken("./testdir/newToken"); +#else + OSToken clearedToken(".\\testdir\\newToken"); +#endif + + CPPUNIT_ASSERT(!clearedToken.isValid()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h new file mode 100644 index 0000000..1155fcf --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/OSTokenTests.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + OSTokenTests.h + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_OSTOKENTESTS_H +#define _SOFTHSM_V2_OSTOKENTESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class OSTokenTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(OSTokenTests); + CPPUNIT_TEST(testNewToken); + CPPUNIT_TEST(testExistingToken); + CPPUNIT_TEST(testNonExistentToken); + CPPUNIT_TEST(testCreateDeleteObjects); + CPPUNIT_TEST(testClearToken); + CPPUNIT_TEST_SUITE_END(); + +public: + void testNewToken(); + void testExistingToken(); + void testNonExistentToken(); + void testCreateDeleteObjects(); + void testClearToken(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_OSTOKENTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp new file mode 100644 index 0000000..9f0f5bd --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.cpp @@ -0,0 +1,911 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectObjectFileTests.cpp + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "ObjectFileTests.h" +#include "ObjectFile.h" +#include "File.h" +#include "Directory.h" +#include "OSAttribute.h" +#include "CryptoFactory.h" +#include "RNG.h" +#include "cryptoki.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(ObjectFileTests); + +// FIXME: all pathnames in this file are *NIX/BSD specific + +void ObjectFileTests::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); +} + +void ObjectFileTests::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void ObjectFileTests::testBoolAttr() +{ + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + bool value2 = false; + bool value3 = true; + bool value4 = true; + bool value5 = false; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SENSITIVE, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_EXTRACTABLE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_NEVER_EXTRACTABLE, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr5)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SENSITIVE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_EXTRACTABLE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_NEVER_EXTRACTABLE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).getBooleanValue() == false); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == false); + + bool value6 = true; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VERIFY, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).getBooleanValue() == value6); + CPPUNIT_ASSERT(testObject.getBooleanValue(CKA_VERIFY, false) == value6); + } +} + +void ObjectFileTests::testULongAttr() +{ + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + unsigned long value1 = 0x12345678; + unsigned long value2 = 0x87654321; + unsigned long value3 = 0x01010101; + unsigned long value4 = 0x10101010; + unsigned long value5 = 0xABCDEF; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS_BITS, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_AUTH_PIN_FLAGS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBPRIME_BITS, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_KEY_TYPE, attr5)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_AUTH_PIN_FLAGS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBPRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_KEY_TYPE)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).isUnsignedLongAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).getUnsignedLongValue() == 0x12345678); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).getUnsignedLongValue() == 0x01010101); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).getUnsignedLongValue() == 0x10101010); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).getUnsignedLongValue() == 0xABCDEF); + + unsigned long value6 = 0x90909090; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_CLASS, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).getUnsignedLongValue() == value6); + CPPUNIT_ASSERT(testObject.getUnsignedLongValue(CKA_CLASS, 0x0) == value6); + } +} + +void ObjectFileTests::testByteStrAttr() +{ + ByteString value1 = "010203040506070809"; + ByteString value2 = "ABABABABABABABABABABABABABABABABAB"; + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value4 = "98A7E5D798A7E5D798A7E5D798A7E5D798A7E5D798A7E5D7"; + ByteString value5 = "ABCDABCDABCDABCDABCDABCDABCDABCD"; + + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_COEFFICIENT, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PUBLIC_EXPONENT, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr5)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_COEFFICIENT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PUBLIC_EXPONENT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).getByteStringValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).getByteStringValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value5); + + ByteString value6 = "909090908080808080807070707070FF"; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ISSUER, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ISSUER).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getByteStringValue(CKA_ISSUER) == value6); + } +} + +void ObjectFileTests::testMechTypeSetAttr() +{ + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + std::set<CK_MECHANISM_TYPE> set; + set.insert(CKM_SHA256); + set.insert(CKM_SHA512); + OSAttribute attr(set); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + std::set<CK_MECHANISM_TYPE> retrieved = + testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue(); + + CPPUNIT_ASSERT(retrieved.size() == 2); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA256) != retrieved.end()); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA384) == retrieved.end()); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA512) != retrieved.end()); + } +} + +void ObjectFileTests::testAttrMapAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattr; + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_TOKEN, attr1)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_PRIME_BITS, attr2)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_VALUE, attr3)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_ALLOWED_MECHANISMS, attr4)); + OSAttribute attra(mattr); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_WRAP_TEMPLATE, attra)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_WRAP_TEMPLATE)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_UNWRAP_TEMPLATE)); + + std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattrb = + testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue(); + CPPUNIT_ASSERT(mattrb.size() == 4); + CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(mattrb.find(CKA_VALUE) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(mattrb.find(CKA_ALLOWED_MECHANISMS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + } +} + +void ObjectFileTests::testMixedAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + } +} + +void ObjectFileTests::testDoubleAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value3a = "466487346943785684957634"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + std::set<CK_MECHANISM_TYPE> value4a; + value4a.insert(CKM_SHA384); + value4a.insert(CKM_SHA512); + + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + bool value1 = false; + unsigned long value2 = 0x76767676; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3a); + OSAttribute attr4(value4a); + + // Change the attributes + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + + // Check the attributes + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + } + + // Now re-read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + bool value1 = false; + unsigned long value2 = 0x76767676; + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + } +} + +void ObjectFileTests::testRefresh() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value3a = "466487346943785684957634"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + std::set<CK_MECHANISM_TYPE> value4a; + value4a.insert(CKM_SHA384); + value4a.insert(CKM_SHA512); + + // Create the test object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + } + + // Now read back the object + { +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + bool value1 = false; + unsigned long value2 = 0x76767676; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3a); + OSAttribute attr4(value4a); + + // Change the attributes + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + + // Check the attributes + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Open the object a second time +#ifndef _WIN32 + ObjectFile testObject2(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject2(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject2.isValid()); + + // Check the attributes on the second instance + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Add an attribute on the second object + ByteString id = "0102010201020102010201020102010201020102"; + + OSAttribute attr5(id); + + CPPUNIT_ASSERT(testObject2.setAttribute(CKA_ID, attr5)); + + // Check the attribute + CPPUNIT_ASSERT(testObject2.attributeExists(CKA_ID)); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ID).getByteStringValue() == id); + + // Now check that the first instance also knows about it + CPPUNIT_ASSERT(testObject.isValid()); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ID)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ID).getByteStringValue() == id); + + // Now change another attribute + unsigned long value2a = 0x89898989; + + OSAttribute attr2a(value2a); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + + // Check the attribute + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + + // Now check that the second instance also knows about the change + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + } +} + +void ObjectFileTests::testCorruptFile() +{ +#ifndef _WIN32 + FILE* stream = fopen("testdir/test.object", "w"); +#else + FILE* stream = fopen("testdir\\test.object", "wb"); +#endif + RNG* rng = CryptoFactory::i()->getRNG(); + ByteString randomData; + + CPPUNIT_ASSERT(stream != NULL); + CPPUNIT_ASSERT(rng->generateRandom(randomData, 312)); + CPPUNIT_ASSERT(fwrite(randomData.const_byte_str(), 1, randomData.size(), stream) == randomData.size()); + CPPUNIT_ASSERT(!fclose(stream)); + +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(!testObject.isValid()); +} + +void ObjectFileTests::testTransactions() +{ + // Create test object instance +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + std::set<CK_MECHANISM_TYPE> value4; + value4.insert(CKM_SHA256); + value4.insert(CKM_SHA512); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + + // Create secondary instance for the same object +#ifndef _WIN32 + ObjectFile testObject2(NULL, "testdir/test.object", "testdir/test.lock"); +#else + ObjectFile testObject2(NULL, "testdir\\test.object", "testdir\\test.lock"); +#endif + + CPPUNIT_ASSERT(testObject2.isValid()); + + // Check that it has the same attributes + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + // New values + bool value1a = false; + unsigned long value2a = 0x12345678; + ByteString value3a = "ABABABABABABABABABABABABABABAB"; + std::set<CK_MECHANISM_TYPE> value4a; + value4a.insert(CKM_SHA384); + value4a.insert(CKM_SHA512); + + OSAttribute attr1a(value1a); + OSAttribute attr2a(value2a); + OSAttribute attr3a(value3a); + OSAttribute attr4a(value4a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(ObjectFile::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4a)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Verify that they are unchanged on the other instance + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + // Commit the transaction + CPPUNIT_ASSERT(testObject.commitTransaction()); + + // Verify that they have now changed on the other instance + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Start transaction on object + CPPUNIT_ASSERT(testObject.startTransaction(ObjectFile::ReadWrite)); + + // Change the attributes + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr4)); + + // Verify that the attributes were set + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4); + + // Verify that they are unchanged on the other instance + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + // Abort the transaction + CPPUNIT_ASSERT(testObject.abortTransaction()); + + // Verify that they are unchanged on both instances + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); + + CPPUNIT_ASSERT(testObject2.isValid()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_VALUE).getByteStringValue() == value3a); + CPPUNIT_ASSERT(testObject2.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue() == value4a); +} + +void ObjectFileTests::testDestroyObjectFails() +{ + // Create test object instance +#ifndef _WIN32 + ObjectFile testObject(NULL, "testdir/test.object", "testdir/test.lock", true); +#else + ObjectFile testObject(NULL, "testdir\\test.object", "testdir\\test.lock", true); +#endif + + CPPUNIT_ASSERT(testObject.isValid()); + + OSObject* testIF = (OSObject*) &testObject; + + CPPUNIT_ASSERT(!testIF->destroyObject()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h new file mode 100644 index 0000000..8342a64 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectFileTests.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectFileTests.h + + Contains test cases to test the object file implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_OBJECTFILETESTS_H +#define _SOFTHSM_V2_OBJECTFILETESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class ObjectFileTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ObjectFileTests); + CPPUNIT_TEST(testBoolAttr); + CPPUNIT_TEST(testULongAttr); + CPPUNIT_TEST(testByteStrAttr); + CPPUNIT_TEST(testMechTypeSetAttr); + CPPUNIT_TEST(testAttrMapAttr); + CPPUNIT_TEST(testMixedAttr); + CPPUNIT_TEST(testDoubleAttr); + CPPUNIT_TEST(testRefresh); + CPPUNIT_TEST(testCorruptFile); + CPPUNIT_TEST(testTransactions); + CPPUNIT_TEST(testDestroyObjectFails); + CPPUNIT_TEST_SUITE_END(); + +public: + void testBoolAttr(); + void testULongAttr(); + void testByteStrAttr(); + void testMechTypeSetAttr(); + void testAttrMapAttr(); + void testMixedAttr(); + void testDoubleAttr(); + void testRefresh(); + void testCorruptFile(); + void testTransactions(); + void testDestroyObjectFails(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_OBJECTFILETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp new file mode 100644 index 0000000..0cad27b --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectStoreTests.cpp + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "ObjectStoreTests.h" +#include "ObjectStore.h" +#include "File.h" +#include "Directory.h" +#include "OSAttribute.h" +#include "OSAttributes.h" +#include "cryptoki.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(ObjectStoreTests); + +// FIXME: all pathnames in this file are *NIX/BSD specific + +void ObjectStoreTests::setUp() +{ + CPPUNIT_ASSERT(!system("mkdir testdir")); +} + +void ObjectStoreTests::tearDown() +{ +#ifndef _WIN32 + CPPUNIT_ASSERT(!system("rm -rf testdir")); +#else + CPPUNIT_ASSERT(!system("rmdir /s /q testdir 2> nul")); +#endif +} + +void ObjectStoreTests::testEmptyStore() +{ + // Create the store for an empty dir +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 0); +} + +void ObjectStoreTests::testNewTokens() +{ + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + + { + // Create an empty store +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 0); + + // Create a new token + ObjectStoreToken* token1 = store.newToken(label1); + + CPPUNIT_ASSERT(token1 != NULL); + + CPPUNIT_ASSERT(store.getTokenCount() == 1); + + // Create another new token + ObjectStoreToken* token2 = store.newToken(label2); + + CPPUNIT_ASSERT(token2 != NULL); + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + } + + // Now reopen that same store +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* token1 = store.getToken(0); + ObjectStoreToken* token2 = store.getToken(1); + + ByteString retrieveLabel1, retrieveLabel2; + + CPPUNIT_ASSERT(token1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(token2->getTokenLabel(retrieveLabel2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel2 == label1)); + CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2)); + + ByteString retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(token1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(token2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); +} + +void ObjectStoreTests::testExistingTokens() +{ + // Create some tokens + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + ByteString serial1 = "0011001100110011"; + ByteString serial2 = "2233223322332233"; + +#ifndef _WIN32 + ObjectStoreToken* token1 = ObjectStoreToken::createToken("./testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken("./testdir", "token2", label2, serial2); +#else + ObjectStoreToken* token1 = ObjectStoreToken::createToken(".\\testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken(".\\testdir", "token2", label2, serial2); +#endif + + CPPUNIT_ASSERT((token1 != NULL) && (token2 != NULL)); + + delete token1; + delete token2; + + // Now associate a store with the test directory +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* retrieveToken1 = store.getToken(0); + ObjectStoreToken* retrieveToken2 = store.getToken(1); + + ByteString retrieveLabel1, retrieveLabel2, retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(retrieveToken1 != NULL); + CPPUNIT_ASSERT(retrieveToken2 != NULL); + + CPPUNIT_ASSERT(retrieveToken1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenLabel(retrieveLabel2)); + CPPUNIT_ASSERT(retrieveToken1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel1 == label2)); + CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2)); + CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2); + CPPUNIT_ASSERT((retrieveSerial1 == serial1) || (retrieveSerial1 == serial2)); + CPPUNIT_ASSERT((retrieveSerial2 == serial1) || (retrieveSerial2 == serial2)); + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); +} + +void ObjectStoreTests::testDeleteToken() +{ + // Create some tokens + ByteString label1 = "DEADC0FFEE"; + ByteString label2 = "DEADBEEF"; + ByteString serial1 = "0011001100110011"; + ByteString serial2 = "2233223322332233"; + +#ifndef _WIN32 + ObjectStoreToken* token1 = ObjectStoreToken::createToken("./testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken("./testdir", "token2", label2, serial2); +#else + ObjectStoreToken* token1 = ObjectStoreToken::createToken(".\\testdir", "token1", label1, serial1); + ObjectStoreToken* token2 = ObjectStoreToken::createToken(".\\testdir", "token2", label2, serial2); +#endif + + CPPUNIT_ASSERT((token1 != NULL) && (token2 != NULL)); + + delete token1; + delete token2; + + // Now associate a store with the test directory +#ifndef _WIN32 + ObjectStore store("./testdir"); +#else + ObjectStore store(".\\testdir"); +#endif + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* retrieveToken1 = store.getToken(0); + ObjectStoreToken* retrieveToken2 = store.getToken(1); + + ByteString retrieveLabel1, retrieveLabel2, retrieveSerial1, retrieveSerial2; + + CPPUNIT_ASSERT(retrieveToken1 != NULL); + CPPUNIT_ASSERT(retrieveToken2 != NULL); + + CPPUNIT_ASSERT(retrieveToken1->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenLabel(retrieveLabel2)); + CPPUNIT_ASSERT(retrieveToken1->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(retrieveToken2->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label1) || (retrieveLabel1 == label2)); + CPPUNIT_ASSERT((retrieveLabel2 == label1) || (retrieveLabel2 == label2)); + CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2); + CPPUNIT_ASSERT((retrieveSerial1 == serial1) || (retrieveSerial1 == serial2)); + CPPUNIT_ASSERT((retrieveSerial2 == serial1) || (retrieveSerial2 == serial2)); + CPPUNIT_ASSERT(retrieveSerial1 != retrieveSerial2); + + // Now, delete token #1 + CPPUNIT_ASSERT(store.destroyToken(retrieveToken1)); + + CPPUNIT_ASSERT(store.getTokenCount() == 1); + + ObjectStoreToken* retrieveToken_ = store.getToken(0); + + ByteString retrieveLabel_,retrieveSerial_; + + CPPUNIT_ASSERT(retrieveToken_->getTokenLabel(retrieveLabel_)); + CPPUNIT_ASSERT(retrieveToken_->getTokenSerial(retrieveSerial_)); + + CPPUNIT_ASSERT(((retrieveLabel_ == label1) && (retrieveSerial_ == serial1)) || + ((retrieveLabel_ == label2) && (retrieveSerial_ == serial2))); + + // Now add a new token + ByteString label3 = "DEADC0FFEEBEEF"; + + // Create a new token + ObjectStoreToken* tokenNew = store.newToken(label3); + + CPPUNIT_ASSERT(tokenNew != NULL); + + CPPUNIT_ASSERT(store.getTokenCount() == 2); + + // Retrieve both tokens and check that both are present + ObjectStoreToken* retrieveToken1_ = store.getToken(0); + ObjectStoreToken* retrieveToken2_ = store.getToken(1); + + CPPUNIT_ASSERT(retrieveToken1_ != NULL); + CPPUNIT_ASSERT(retrieveToken2_ != NULL); + + CPPUNIT_ASSERT(retrieveToken1_->getTokenLabel(retrieveLabel1)); + CPPUNIT_ASSERT(retrieveToken2_->getTokenLabel(retrieveLabel2)); + CPPUNIT_ASSERT(retrieveToken1_->getTokenSerial(retrieveSerial1)); + CPPUNIT_ASSERT(retrieveToken2_->getTokenSerial(retrieveSerial2)); + + CPPUNIT_ASSERT((retrieveLabel1 == label3) || (retrieveLabel2 == label3)); + CPPUNIT_ASSERT(((retrieveLabel1 == label1) && (retrieveLabel2 != label2)) || + ((retrieveLabel1 == label2) && (retrieveLabel2 != label1))); + CPPUNIT_ASSERT(retrieveLabel1 != retrieveLabel2); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h new file mode 100644 index 0000000..3f03c5a --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/ObjectStoreTests.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + ObjectStoreTests.h + + Contains test cases to test the object store implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_OBJECTSTORETESTS_H +#define _SOFTHSM_V2_OBJECTSTORETESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class ObjectStoreTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(ObjectStoreTests); + CPPUNIT_TEST(testEmptyStore); + CPPUNIT_TEST(testNewTokens); + CPPUNIT_TEST(testExistingTokens); + CPPUNIT_TEST(testDeleteToken); + CPPUNIT_TEST_SUITE_END(); + +public: + void testEmptyStore(); + void testNewTokens(); + void testExistingTokens(); + void testDeleteToken(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_OBJECTSTORETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp new file mode 100644 index 0000000..2c41eb0 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectStoreTests.cpp + + Contains test cases to test the session object store implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include <memory> +#include "SessionObjectStoreTests.h" +#include "SessionObjectStore.h" +#include "SessionObject.h" +#include "OSAttribute.h" +#include "OSAttributes.h" +#include "cryptoki.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(SessionObjectStoreTests); + +void SessionObjectStoreTests::setUp() +{ +} + +void SessionObjectStoreTests::tearDown() +{ +} + +void SessionObjectStoreTests::testCreateDeleteObjects() +{ + // Test IDs + ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" }; + OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] }; + ByteString label = "AABBCCDDEEFF"; + ByteString serial = "1234567890"; + + // Get access to the session object store + SessionObjectStore* testStore = new SessionObjectStore(); + + // Create 3 objects in the store + SessionObject* obj1 = testStore->createObject(1, 1); + CPPUNIT_ASSERT(obj1 != NULL); + SessionObject* obj2 = testStore->createObject(1, 1); + CPPUNIT_ASSERT(obj2 != NULL); + SessionObject* obj3 = testStore->createObject(1, 1); + CPPUNIT_ASSERT(obj3 != NULL); + + // Now set the IDs of the 3 objects + obj1->setAttribute(CKA_ID, idAtt[0]); + obj2->setAttribute(CKA_ID, idAtt[1]); + obj3->setAttribute(CKA_ID, idAtt[2]); + + // Check that the store contains 3 objects + CPPUNIT_ASSERT(testStore->getObjects().size() == 3); + + // Check that all three objects are distinct and present + std::set<SessionObject*> objects = testStore->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + for (int j = 0; j < 3; j++) + { + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j]) + { + present1[j] = true; + } + } + } + + for (int j = 0; j < 3; j++) + { + CPPUNIT_ASSERT(present1[j] == true); + } + + // Now delete the second object + for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[1]) + { + CPPUNIT_ASSERT(testStore->deleteObject(*i)); + break; + } + } + + // Verify that it was indeed removed + CPPUNIT_ASSERT(testStore->getObjects().size() == 2); + + objects = testStore->getObjects(); + bool present3[2] = { false, false }; + + for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present3[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present3[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present3[j] == true); + } + + delete testStore; +} + +void SessionObjectStoreTests::testMultiSession() +{ + // Get access to the store + SessionObjectStore* store = new SessionObjectStore(); + + // Check that the store is empty + CPPUNIT_ASSERT(store->getObjects().size() == 0); + + // Test IDs + ByteString id[5] = { "112233445566", "AABBCCDDEEFF", "ABABABABABAB", "557788991122", "005500550055" }; + OSAttribute idAtt[5] = { id[0], id[1], id[2], id[3], id[4] }; + + // Create 3 objects in the store for three different sessions + SessionObject* obj1 = store->createObject(1, 1); + CPPUNIT_ASSERT(obj1 != NULL); + SessionObject* obj2 = store->createObject(1, 2); + CPPUNIT_ASSERT(obj2 != NULL); + SessionObject* obj3 = store->createObject(1, 3); + CPPUNIT_ASSERT(obj3 != NULL); + + // Now set the IDs of the 3 objects + obj1->setAttribute(CKA_ID, idAtt[0]); + obj2->setAttribute(CKA_ID, idAtt[1]); + obj3->setAttribute(CKA_ID, idAtt[2]); + + // Check that the store contains 3 objects + CPPUNIT_ASSERT(store->getObjects().size() == 3); + + // Check that all three objects are distinct and present + std::set<SessionObject*> objects = store->getObjects(); + bool present1[3] = { false, false, false }; + + for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + for (int j = 0; j < 3; j++) + { + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[j]) + { + present1[j] = true; + } + } + } + + for (int j = 0; j < 3; j++) + { + CPPUNIT_ASSERT(present1[j] == true); + } + + // Now indicate that the second session has been closed + store->sessionClosed(2); + + // Verify that it was indeed removed + CPPUNIT_ASSERT(store->getObjects().size() == 2); + + objects = store->getObjects(); + bool present3[2] = { false, false }; + + for (std::set<SessionObject*>::iterator i = objects.begin(); i != objects.end(); i++) + { + ByteString retrievedId; + + CPPUNIT_ASSERT((*i)->isValid()); + CPPUNIT_ASSERT((*i)->attributeExists(CKA_ID)); + + CPPUNIT_ASSERT((*i)->getAttribute(CKA_ID).isByteStringAttribute()); + + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[0]) + { + present3[0] = true; + } + if ((*i)->getAttribute(CKA_ID).getByteStringValue() == id[2]) + { + present3[1] = true; + } + } + + for (int j = 0; j < 2; j++) + { + CPPUNIT_ASSERT(present3[j] == true); + } + + // Create two more objects for session 7 + SessionObject* obj4 = store->createObject(1, 7); + CPPUNIT_ASSERT(obj4 != NULL); + SessionObject* obj5 = store->createObject(1, 7); + CPPUNIT_ASSERT(obj5 != NULL); + + CPPUNIT_ASSERT(store->getObjects().size() == 4); + + // Close session 1 + store->sessionClosed(1); + + CPPUNIT_ASSERT(store->getObjects().size() == 3); + + objects = store->getObjects(); + + CPPUNIT_ASSERT(objects.find(obj1) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj2) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj3) != objects.end()); + CPPUNIT_ASSERT(objects.find(obj4) != objects.end()); + CPPUNIT_ASSERT(objects.find(obj5) != objects.end()); + + CPPUNIT_ASSERT(!obj1->isValid()); + CPPUNIT_ASSERT(!obj2->isValid()); + CPPUNIT_ASSERT(obj3->isValid()); + CPPUNIT_ASSERT(obj4->isValid()); + CPPUNIT_ASSERT(obj5->isValid()); + + // Close session 7 + store->sessionClosed(7); + + CPPUNIT_ASSERT(store->getObjects().size() == 1); + + objects = store->getObjects(); + + CPPUNIT_ASSERT(objects.find(obj1) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj2) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj3) != objects.end()); + CPPUNIT_ASSERT(objects.find(obj4) == objects.end()); + CPPUNIT_ASSERT(objects.find(obj5) == objects.end()); + + CPPUNIT_ASSERT(!obj1->isValid()); + CPPUNIT_ASSERT(!obj2->isValid()); + CPPUNIT_ASSERT(obj3->isValid()); + CPPUNIT_ASSERT(!obj4->isValid()); + CPPUNIT_ASSERT(!obj5->isValid()); + + delete store; +} + +void SessionObjectStoreTests::testWipeStore() +{ + // Get access to the store + SessionObjectStore* store = new SessionObjectStore(); + + // Check that the store is empty + CPPUNIT_ASSERT(store->getObjects().size() == 0); + + // Create 3 objects in the store for three different sessions + SessionObject* obj1 = store->createObject(1, 1); + CPPUNIT_ASSERT(obj1 != NULL); + SessionObject* obj2 = store->createObject(1, 2); + CPPUNIT_ASSERT(obj2 != NULL); + SessionObject* obj3 = store->createObject(1, 3); + CPPUNIT_ASSERT(obj3 != NULL); + + // Wipe the store + store->clearStore(); + + // Check that the store is empty + CPPUNIT_ASSERT(store->getObjects().size() == 0); + + delete store; +} + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h new file mode 100644 index 0000000..374eeaa --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectStoreTests.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectStoreTests.h + + Contains test cases to test the session object store implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H +#define _SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class SessionObjectStoreTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SessionObjectStoreTests); + CPPUNIT_TEST(testCreateDeleteObjects); + CPPUNIT_TEST(testMultiSession); + CPPUNIT_TEST(testWipeStore); + CPPUNIT_TEST_SUITE_END(); + +public: + void testCreateDeleteObjects(); + void testMultiSession(); + void testWipeStore(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_SESSIONOBJECTSTORETESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp new file mode 100644 index 0000000..6183ec6 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectTests.cpp + + Contains test cases to test the session object implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "SessionObjectTests.h" +#include "SessionObject.h" +#include "File.h" +#include "Directory.h" +#include "OSAttribute.h" +#include "cryptoki.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(SessionObjectTests); + +void SessionObjectTests::setUp() +{ +} + +void SessionObjectTests::tearDown() +{ +} + +void SessionObjectTests::testBoolAttr() +{ + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + bool value2 = false; + bool value3 = true; + bool value4 = true; + bool value5 = false; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SENSITIVE, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_EXTRACTABLE, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_NEVER_EXTRACTABLE, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SIGN, attr5)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SENSITIVE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_EXTRACTABLE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_NEVER_EXTRACTABLE)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SIGN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).isBooleanAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SENSITIVE).getBooleanValue() == false); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_EXTRACTABLE).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_NEVER_EXTRACTABLE).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SIGN).getBooleanValue() == false); + + bool value6 = true; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VERIFY, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VERIFY).getBooleanValue() == value6); + CPPUNIT_ASSERT(testObject.getBooleanValue(CKA_VERIFY, false) == value6); +} + +void SessionObjectTests::testULongAttr() +{ + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + unsigned long value1 = 0x12345678; + unsigned long value2 = 0x87654321; + unsigned long value3 = 0x01010101; + unsigned long value4 = 0x10101010; + unsigned long value5 = 0xABCDEF; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS_BITS, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_AUTH_PIN_FLAGS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBPRIME_BITS, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_KEY_TYPE, attr5)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_AUTH_PIN_FLAGS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBPRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_KEY_TYPE)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).isUnsignedLongAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS_BITS).getUnsignedLongValue() == 0x12345678); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_AUTH_PIN_FLAGS).getUnsignedLongValue() == 0x01010101); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBPRIME_BITS).getUnsignedLongValue() == 0x10101010); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_KEY_TYPE).getUnsignedLongValue() == 0xABCDEF); + + unsigned long value6 = 0x90909090; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_CLASS, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_CLASS).getUnsignedLongValue() == value6); + CPPUNIT_ASSERT(testObject.getUnsignedLongValue(CKA_CLASS, 0x0) == value6); +} + +void SessionObjectTests::testByteStrAttr() +{ + ByteString value1 = "010203040506070809"; + ByteString value2 = "ABABABABABABABABABABABABABABABABAB"; + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value4 = "98A7E5D798A7E5D798A7E5D798A7E5D798A7E5D798A7E5D7"; + ByteString value5 = "ABCDABCDABCDABCDABCDABCDABCDABCD"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + OSAttribute attr4(value4); + OSAttribute attr5(value5); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_MODULUS, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_COEFFICIENT, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PUBLIC_EXPONENT, attr4)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_SUBJECT, attr5)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_MODULUS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_COEFFICIENT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PUBLIC_EXPONENT)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_SUBJECT)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_MODULUS).getByteStringValue() == value1); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_COEFFICIENT).getByteStringValue() == value2); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PUBLIC_EXPONENT).getByteStringValue() == value4); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_SUBJECT).getByteStringValue() == value5); + + ByteString value6 = "909090908080808080807070707070FF"; + OSAttribute attr6(value6); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ISSUER, attr6)); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ISSUER).isByteStringAttribute()); + CPPUNIT_ASSERT(testObject.getByteStringValue(CKA_ISSUER) == value6); +} + +void SessionObjectTests::testMechTypeSetAttr() +{ + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + std::set<CK_MECHANISM_TYPE> set; + set.insert(CKM_SHA256); + set.insert(CKM_SHA512); + + OSAttribute attr(set); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_ALLOWED_MECHANISMS, attr)); + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_ALLOWED_MECHANISMS)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_ALLOWED_MECHANISMS).isMechanismTypeSetAttribute()); + + std::set<CK_MECHANISM_TYPE> retrieved = + testObject.getAttribute(CKA_ALLOWED_MECHANISMS).getMechanismTypeSetValue(); + + CPPUNIT_ASSERT(retrieved.size() == 2); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA256) != retrieved.end()); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA384) == retrieved.end()); + CPPUNIT_ASSERT(retrieved.find(CKM_SHA512) != retrieved.end()); +} + +void SessionObjectTests::testAttrMapAttr() +{ + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattr; + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_TOKEN, attr1)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_PRIME_BITS, attr2)); + mattr.insert(std::pair<CK_ATTRIBUTE_TYPE,OSAttribute> (CKA_VALUE_BITS, attr3)); + OSAttribute attra(mattr); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_WRAP_TEMPLATE, attra)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_WRAP_TEMPLATE)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_UNWRAP_TEMPLATE)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_WRAP_TEMPLATE).isAttributeMapAttribute()); + + std::map<CK_ATTRIBUTE_TYPE,OSAttribute> mattrb = + testObject.getAttribute(CKA_WRAP_TEMPLATE).getAttributeMapValue(); + CPPUNIT_ASSERT(mattrb.size() == 3); + CPPUNIT_ASSERT(mattrb.find(CKA_TOKEN) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(mattrb.find(CKA_PRIME_BITS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(mattrb.find(CKA_VALUE_BITS) != mattrb.end()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE_BITS).isByteStringAttribute()); + CPPUNIT_ASSERT(mattrb.at(CKA_VALUE_BITS).getByteStringValue() == value3); + +} + +void SessionObjectTests::testMixedAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); +} + +void SessionObjectTests::testDoubleAttr() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + ByteString value3a = "466487346943785684957634"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); + + bool value1a = false; + unsigned long value2a = 0x76767676; + + OSAttribute attr1a(value1a); + OSAttribute attr2a(value2a); + OSAttribute attr3a(value3a); + + // Change the attributes + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2a)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3a)); + + // Check the attributes + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == value1a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == value2a); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3a); + + CPPUNIT_ASSERT(testObject.isValid()); +} + +void SessionObjectTests::testCloseSession() +{ + ByteString value3 = "BDEBDBEDBBDBEBDEBE792759537328"; + + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + bool value1 = true; + unsigned long value2 = 0x87654321; + + OSAttribute attr1(value1); + OSAttribute attr2(value2); + OSAttribute attr3(value3); + + CPPUNIT_ASSERT(testObject.setAttribute(CKA_TOKEN, attr1)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_PRIME_BITS, attr2)); + CPPUNIT_ASSERT(testObject.setAttribute(CKA_VALUE_BITS, attr3)); + + CPPUNIT_ASSERT(testObject.isValid()); + + CPPUNIT_ASSERT(testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(testObject.attributeExists(CKA_VALUE_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_ID)); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).isBooleanAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).isUnsignedLongAttribute()); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).isByteStringAttribute()); + + CPPUNIT_ASSERT(testObject.getAttribute(CKA_TOKEN).getBooleanValue() == true); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_PRIME_BITS).getUnsignedLongValue() == 0x87654321); + CPPUNIT_ASSERT(testObject.getAttribute(CKA_VALUE_BITS).getByteStringValue() == value3); + + // Now close the session + testObject.removeOnSessionClose(1); + + CPPUNIT_ASSERT(!testObject.isValid()); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_TOKEN)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_PRIME_BITS)); + CPPUNIT_ASSERT(!testObject.attributeExists(CKA_VALUE_BITS)); +} + +void SessionObjectTests::testDestroyObjectFails() +{ + // Create test object instance + SessionObject testObject(NULL, 1, 1); + + CPPUNIT_ASSERT(testObject.isValid()); + + OSObject* testIF = (OSObject*) &testObject; + + CPPUNIT_ASSERT(!testIF->destroyObject()); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h new file mode 100644 index 0000000..76fa02e --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/SessionObjectTests.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + SessionObjectTests.h + + Contains test cases to test the session object implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_SESSIONOBJECTTESTS_H +#define _SOFTHSM_V2_SESSIONOBJECTTESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class SessionObjectTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(SessionObjectTests); + CPPUNIT_TEST(testBoolAttr); + CPPUNIT_TEST(testULongAttr); + CPPUNIT_TEST(testByteStrAttr); + CPPUNIT_TEST(testMechTypeSetAttr); + CPPUNIT_TEST(testAttrMapAttr); + CPPUNIT_TEST(testMixedAttr); + CPPUNIT_TEST(testDoubleAttr); + CPPUNIT_TEST(testCloseSession); + CPPUNIT_TEST(testDestroyObjectFails); + CPPUNIT_TEST_SUITE_END(); + +public: + void testBoolAttr(); + void testULongAttr(); + void testByteStrAttr(); + void testMechTypeSetAttr(); + void testAttrMapAttr(); + void testMixedAttr(); + void testDoubleAttr(); + void testCloseSession(); + void testDestroyObjectFails(); + + void setUp(); + void tearDown(); +}; + +#endif // !_SOFTHSM_V2_SESSIONOBJECTTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp b/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp new file mode 100644 index 0000000..84a49d2 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/UUIDTests.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + UUIDTests.cpp + + Contains test cases to test the UUID implementation + *****************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <cppunit/extensions/HelperMacros.h> +#include "UUIDTests.h" +#include "UUID.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(UUIDTests); + +void UUIDTests::setUp() +{ +} + +void UUIDTests::tearDown() +{ +} + +void UUIDTests::testUUID() +{ + std::string uuid1 = UUID::newUUID(); + std::string uuid2 = UUID::newUUID(); + std::string uuid3 = UUID::newUUID(); + + CPPUNIT_ASSERT((uuid1.size() == 36) && (uuid2.size() == 36) && (uuid3.size() == 36)); + + CPPUNIT_ASSERT(uuid1.compare(uuid2)); + CPPUNIT_ASSERT(uuid1.compare(uuid3)); + CPPUNIT_ASSERT(uuid2.compare(uuid3)); +} + diff --git a/SoftHSMv2/src/lib/object_store/test/UUIDTests.h b/SoftHSMv2/src/lib/object_store/test/UUIDTests.h new file mode 100644 index 0000000..374d509 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/UUIDTests.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + UUIDTests.h + + Contains test cases to test the UUID implementation + *****************************************************************************/ + +#ifndef _SOFTHSM_V2_UUIDTESTS_H +#define _SOFTHSM_V2_UUIDTESTS_H + +#include <cppunit/extensions/HelperMacros.h> + +class UUIDTests : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(UUIDTests); + CPPUNIT_TEST(testUUID); + CPPUNIT_TEST_SUITE_END(); + +public: + void testUUID(); + + void setUp(); + void tearDown(); + +private: +}; + +#endif // !_SOFTHSM_V2_UUIDTESTS_H + diff --git a/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp b/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp new file mode 100644 index 0000000..7e4b854 --- /dev/null +++ b/SoftHSMv2/src/lib/object_store/test/objstoretest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 SURFnet bv + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************************************************************** + objstoretest.cpp + + The main test executor for tests on the object store in SoftHSM v2 + *****************************************************************************/ + +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <cppunit/ui/text/TestRunner.h> +#include <cppunit/TestResult.h> +#include <cppunit/TestResultCollector.h> +#include <cppunit/XmlOutputter.h> +#include <fstream> + +#include "config.h" +#include "MutexFactory.h" +#include "SecureMemoryRegistry.h" + +#if defined(WITH_OPENSSL) +#include "OSSLCryptoFactory.h" +#else +#include "BotanCryptoFactory.h" +#endif + +// Initialise the one-and-only instance +#ifdef HAVE_CXX11 + +std::unique_ptr<MutexFactory> MutexFactory::instance(nullptr); +std::unique_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(nullptr); +#if defined(WITH_OPENSSL) +std::unique_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(nullptr); +#else +std::unique_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(nullptr); +#endif + +#else + +std::auto_ptr<MutexFactory> MutexFactory::instance(NULL); +std::auto_ptr<SecureMemoryRegistry> SecureMemoryRegistry::instance(NULL); +#if defined(WITH_OPENSSL) +std::auto_ptr<OSSLCryptoFactory> OSSLCryptoFactory::instance(NULL); +#else +std::auto_ptr<BotanCryptoFactory> BotanCryptoFactory::instance(NULL); +#endif + +#endif + +int main(int /*argc*/, char** /*argv*/) +{ + CppUnit::TestResult controller; + CppUnit::TestResultCollector result; + CppUnit::TextUi::TestRunner runner; + controller.addListener(&result); + CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + + runner.addTest(registry.makeTest()); + runner.run(controller); + + std::ofstream xmlFileOut("test-results.xml"); + CppUnit::XmlOutputter xmlOut(&result, xmlFileOut); + xmlOut.write(); + + CryptoFactory::reset(); + + return result.wasSuccessful() ? 0 : 1; +} |