aboutsummaryrefslogtreecommitdiffstats
path: root/SoftHSMv2/src/lib/data_mgr
diff options
context:
space:
mode:
Diffstat (limited to 'SoftHSMv2/src/lib/data_mgr')
-rw-r--r--SoftHSMv2/src/lib/data_mgr/ByteString.cpp365
-rw-r--r--SoftHSMv2/src/lib/data_mgr/ByteString.h131
-rw-r--r--SoftHSMv2/src/lib/data_mgr/Makefile.am17
-rw-r--r--SoftHSMv2/src/lib/data_mgr/RFC4880.cpp110
-rw-r--r--SoftHSMv2/src/lib/data_mgr/RFC4880.h54
-rw-r--r--SoftHSMv2/src/lib/data_mgr/SecureAllocator.h203
-rw-r--r--SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp537
-rw-r--r--SoftHSMv2/src/lib/data_mgr/SecureDataManager.h154
-rw-r--r--SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp142
-rw-r--r--SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h73
-rw-r--r--SoftHSMv2/src/lib/data_mgr/salloc.cpp126
-rw-r--r--SoftHSMv2/src/lib/data_mgr/salloc.h56
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp356
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h71
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/Makefile.am27
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp116
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h56
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp207
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h56
-rw-r--r--SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp91
20 files changed, 2948 insertions, 0 deletions
diff --git a/SoftHSMv2/src/lib/data_mgr/ByteString.cpp b/SoftHSMv2/src/lib/data_mgr/ByteString.cpp
new file mode 100644
index 0000000..e133f71
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/ByteString.cpp
@@ -0,0 +1,365 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ByteString.cpp
+
+ A string class for byte strings stored in securely allocated memory
+ *****************************************************************************/
+
+#include <algorithm>
+#include <string>
+#include <stdio.h>
+#include "config.h"
+#include "log.h"
+#include "ByteString.h"
+
+// Constructors
+ByteString::ByteString()
+{
+}
+
+ByteString::ByteString(const unsigned char* bytes, const size_t bytesLen)
+{
+ byteString.resize(bytesLen);
+
+ if (bytesLen > 0)
+ memcpy(&byteString[0], bytes, bytesLen);
+}
+
+ByteString::ByteString(const char* hexString)
+{
+ std::string hex = std::string(hexString);
+
+ if (hex.size() % 2 != 0)
+ {
+ hex = "0" + hex;
+ }
+
+ for (size_t i = 0; i < hex.size(); i += 2)
+ {
+ std::string byteStr;
+ byteStr += hex[i];
+ byteStr += hex[i+1];
+
+ unsigned char byteVal = (unsigned char) strtoul(byteStr.c_str(), NULL, 16);
+
+ this->operator+=(byteVal);
+ }
+}
+
+ByteString::ByteString(const unsigned long longValue)
+{
+ unsigned long setValue = longValue;
+
+ // Convert the value to a big-endian byte string; N.B.: this code assumes that unsigned long
+ // values are stored as a 64-bit value, which is a safe assumption on modern systems. It will
+ // also properly handle a 32-bit value and will simply store 4 zeroes at the front of the
+ // string. If at some point in time we get 128-bit architectures, the top 8 bytes of the value
+ // will be discarded... (but hey, 640K is enough for everybody, right?)
+ //
+ // The reason for coding it this way is that implementations of SoftHSM will maintain
+ // binary compatibility between eachothers background storage (i.e. a 32-bit SoftHSM version can
+ // read the storage of a 64-bit version and vice versa under the assumption that the stored
+ // values never exceed 32-bits, which is likely since these values are only used to encode
+ // byte string lengths)
+ unsigned char byteStrIn[8];
+
+ for (size_t i = 0; i < 8; i++)
+ {
+ byteStrIn[7-i] = (unsigned char) (setValue & 0xFF);
+ setValue >>= 8;
+ }
+
+ byteString.resize(8);
+ memcpy(&byteString[0], byteStrIn, 8);
+}
+
+ByteString::ByteString(const ByteString& in)
+{
+ this->byteString = in.byteString;
+}
+
+// Append data
+ByteString& ByteString::operator+=(const ByteString& append)
+{
+ size_t curLen = byteString.size();
+ size_t toAdd = append.byteString.size();
+ size_t newLen = curLen + toAdd;
+
+ byteString.resize(newLen);
+
+ if (toAdd > 0)
+ memcpy(&byteString[curLen], &append.byteString[0], toAdd);
+
+ return *this;
+}
+
+ByteString& ByteString::operator+=(const unsigned char byte)
+{
+ byteString.push_back(byte);
+
+ return *this;
+}
+
+// XORing
+ByteString& ByteString::operator^=(const ByteString& rhs)
+{
+ size_t xorLen = std::min(this->size(), rhs.size());
+
+ for (size_t i = 0; i < xorLen; i++)
+ {
+ byteString[i] ^= rhs.const_byte_str()[i];
+ }
+
+ return *this;
+}
+
+// Return a substring
+ByteString ByteString::substr(const size_t start, const size_t len /* = SIZE_T_MAX */) const
+{
+ size_t retLen = std::min(len, byteString.size() - start);
+
+ if (start >= byteString.size())
+ {
+ return ByteString();
+ }
+ else
+ {
+ return ByteString(&byteString[start], retLen);
+ }
+}
+
+// Add data
+ByteString operator+(const ByteString& lhs, const ByteString& rhs)
+{
+ ByteString rv = lhs;
+ rv += rhs;
+
+ return rv;
+}
+
+ByteString operator+(const unsigned char lhs, const ByteString& rhs)
+{
+ ByteString rv(&lhs, 1);
+ rv += rhs;
+
+ return rv;
+}
+
+ByteString operator+(const ByteString& lhs, const unsigned char rhs)
+{
+ ByteString rv = lhs;
+ rv += rhs;
+
+ return rv;
+}
+
+// Array operator
+unsigned char& ByteString::operator[](size_t pos)
+{
+ return byteString[pos];
+}
+
+// Return the byte string data
+unsigned char* ByteString::byte_str()
+{
+ return &byteString[0];
+}
+
+// Return the const byte string
+const unsigned char* ByteString::const_byte_str() const
+{
+ return (const unsigned char*) &byteString[0];
+}
+
+// Return a hexadecimal character representation of the string
+std::string ByteString::hex_str() const
+{
+ std::string rv;
+ char hex[3];
+
+ for (size_t i = 0; i < byteString.size(); i++)
+ {
+ sprintf(hex, "%02X", byteString[i]);
+
+ rv += hex;
+ }
+
+ return rv;
+}
+
+// Return the long value
+unsigned long ByteString::long_val() const
+{
+ // Convert the first 8 bytes of the string to an unsigned long value
+ unsigned long rv = 0;
+
+ for (size_t i = 0; i < std::min(size_t(8), byteString.size()); i++)
+ {
+ rv <<= 8;
+ rv += byteString[i];
+ }
+
+ return rv;
+}
+
+// Cut of the first part of the string and convert it to a long value
+unsigned long ByteString::firstLong()
+{
+ unsigned long rv = long_val();
+
+ split(8);
+
+ return rv;
+}
+
+// Split of the specified part of the string as a separate byte string
+ByteString ByteString::split(size_t len)
+{
+ ByteString rv = substr(0, len);
+
+ size_t newSize = (byteString.size() > len) ? (byteString.size() - len) : 0;
+
+ if (newSize > 0)
+ {
+ for (size_t i = 0; i < newSize; i++)
+ {
+ byteString[i] = byteString[i + len];
+ }
+ }
+
+ byteString.resize(newSize);
+
+ return rv;
+}
+
+// The size of the byte string in bits
+size_t ByteString::bits() const
+{
+ size_t bits = byteString.size() * 8;
+
+ if (bits == 0) return 0;
+
+ for (size_t i = 0; i < byteString.size(); i++)
+ {
+ unsigned char byte = byteString[i];
+
+ for (unsigned char mask = 0x80; mask > 0; mask >>= 1)
+ {
+ if ((byte & mask) == 0)
+ {
+ bits--;
+ }
+ else
+ {
+ return bits;
+ }
+ }
+ }
+
+ return bits;
+}
+
+// The size of the byte string in bytes
+size_t ByteString::size() const
+{
+ return byteString.size();
+}
+
+void ByteString::resize(const size_t newSize)
+{
+ byteString.resize(newSize);
+}
+
+void ByteString::wipe(const size_t newSize /* = 0 */)
+{
+ this->resize(newSize);
+
+ if (!byteString.empty())
+ memset(&byteString[0], 0x00, byteString.size());
+}
+
+// Comparison
+bool ByteString::operator==(const ByteString& compareTo) const
+{
+ if (compareTo.size() != this->size())
+ {
+ return false;
+ }
+ else if (this->size() == 0)
+ {
+ return true;
+ }
+
+ return (memcmp(&byteString[0], &compareTo.byteString[0], this->size()) == 0);
+}
+
+bool ByteString::operator!=(const ByteString& compareTo) const
+{
+ if (compareTo.size() != this->size())
+ {
+ return true;
+ }
+ else if (this->size() == 0)
+ {
+ return false;
+ }
+
+ return (memcmp(&byteString[0], &compareTo.byteString[0], this->size()) != 0);
+}
+
+// XOR data
+ByteString operator^(const ByteString& lhs, const ByteString& rhs)
+{
+ size_t xorLen = std::min(lhs.size(), rhs.size());
+ ByteString rv;
+
+ for (size_t i = 0; i < xorLen; i++)
+ {
+ rv += lhs.const_byte_str()[i] ^ rhs.const_byte_str()[i];
+ }
+
+ return rv;
+}
+
+// Serialisation/deserialisation
+ByteString ByteString::serialise() const
+{
+ ByteString len((unsigned long) size());
+
+ return len + *this;
+}
+
+/* static */ ByteString ByteString::chainDeserialise(ByteString& serialised)
+{
+ size_t len = (size_t) serialised.firstLong();
+
+ ByteString rv = serialised.split(len);
+
+ return rv;
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/ByteString.h b/SoftHSMv2/src/lib/data_mgr/ByteString.h
new file mode 100644
index 0000000..2c2ef33
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/ByteString.h
@@ -0,0 +1,131 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ByteString.h
+
+ A string class for byte strings stored in securely allocated memory
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BYTESTRING_H
+#define _SOFTHSM_V2_BYTESTRING_H
+
+#include <cstddef>
+#include <vector>
+#include <string>
+#include <stdlib.h>
+#include <limits.h>
+#include "config.h"
+#include "SecureAllocator.h"
+#include "Serialisable.h"
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ((size_t) -1)
+#endif // !SIZE_T_MAX
+
+class ByteString
+{
+public:
+ // Constructors
+ ByteString();
+
+ ByteString(const unsigned char* bytes, const size_t bytesLen);
+
+ ByteString(const char* hexString);
+
+ ByteString(const unsigned long longValue);
+
+ ByteString(const ByteString& in);
+
+ // Destructor
+ virtual ~ByteString() { }
+
+ // Append data
+ ByteString& operator+=(const ByteString& append);
+ ByteString& operator+=(const unsigned char byte);
+
+ // Return a substring
+ ByteString substr(const size_t start, const size_t len = SIZE_T_MAX) const;
+
+ // Array operator
+ unsigned char& operator[](size_t pos);
+
+ // Return the byte string
+ unsigned char* byte_str();
+
+ // Return the const byte string
+ const unsigned char* const_byte_str() const;
+
+ // Return a hexadecimal character representation of the string
+ std::string hex_str() const;
+
+ // Return the long value
+ unsigned long long_val() const;
+
+ // Cut of the first part of the string and convert it to a long value
+ unsigned long firstLong();
+
+ // Split of the specified part of the string as a separate byte string
+ ByteString split(size_t len);
+
+ // Return the size in bits
+ size_t bits() const;
+
+ // Return the size in bytes
+ size_t size() const;
+
+ // Resize
+ void resize(const size_t newSize);
+
+ // Wipe
+ void wipe(const size_t newSize = 0);
+
+ // Comparison
+ bool operator==(const ByteString& compareTo) const;
+ bool operator!=(const ByteString& compareTo) const;
+
+ // XORing
+ ByteString& operator^=(const ByteString& rhs);
+
+ // Serialisation/deserialisation
+ virtual ByteString serialise() const;
+
+ static ByteString chainDeserialise(ByteString& serialised);
+
+private:
+ std::vector<unsigned char, SecureAllocator<unsigned char> > byteString;
+};
+
+// Add data
+ByteString operator+(const ByteString& lhs, const ByteString& rhs);
+ByteString operator+(const unsigned char lhs, const ByteString& rhs);
+ByteString operator+(const ByteString& lhs, const unsigned char rhs);
+
+// XOR data
+ByteString operator^(const ByteString& lhs, const ByteString& rhs);
+
+#endif // !_SOFTHSM_V2_BYTESTRING_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/Makefile.am b/SoftHSMv2/src/lib/data_mgr/Makefile.am
new file mode 100644
index 0000000..85aa4d7
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/Makefile.am
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+AM_CPPFLAGS = -I$(srcdir)/.. \
+ -I$(srcdir)/../crypto \
+ -I$(srcdir)/../common \
+ -I$(srcdir)/../pkcs11
+
+noinst_LTLIBRARIES = libsofthsm_datamgr.la
+libsofthsm_datamgr_la_SOURCES = ByteString.cpp \
+ RFC4880.cpp \
+ salloc.cpp \
+ SecureDataManager.cpp \
+ SecureMemoryRegistry.cpp
+
+SUBDIRS = test
+
+EXTRA_DIST = $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/data_mgr/RFC4880.cpp b/SoftHSMv2/src/lib/data_mgr/RFC4880.cpp
new file mode 100644
index 0000000..9ea23bd
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/RFC4880.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RFC4880.cpp
+
+ Implements a secure password-based key derivation scheme. It is not a generic
+ implementation of the RFC but only generates 256-bit AES keys according to
+ the "iterated and salted" scheme.
+ *****************************************************************************/
+
+#include "config.h"
+#include "RFC4880.h"
+#include "CryptoFactory.h"
+#include "HashAlgorithm.h"
+
+// This function derives a 256-bit AES key from the supplied password data
+bool RFC4880::PBEDeriveKey(const ByteString& password, ByteString& salt, AESKey** ppKey)
+{
+ // Check that a proper salt value was supplied; it should be at least 8 bytes long
+ if (salt.size() < 8)
+ {
+ ERROR_MSG("Insufficient salt data supplied for password-based encryption");
+
+ return false;
+ }
+
+ // Check other parameters
+ if ((password.size() == 0) || (ppKey == NULL))
+ {
+ return false;
+ }
+
+ // Determine the iteration count based on the last byte of the salt
+ unsigned int iter = PBE_ITERATION_BASE_COUNT + salt[salt.size() - 1];
+
+ // Get a hash instance
+ HashAlgorithm* hash = CryptoFactory::i()->getHashAlgorithm(HashAlgo::SHA256);
+
+ if (hash == NULL)
+ {
+ ERROR_MSG("Could not get a SHA-256 instance");
+
+ return false;
+ }
+
+ // Perform the first iteration which takes as input the salt value and
+ // the password
+ ByteString intermediate;
+
+ if (!hash->hashInit() ||
+ !hash->hashUpdate(salt) ||
+ !hash->hashUpdate(password) ||
+ !hash->hashFinal(intermediate))
+ {
+ ERROR_MSG("Hashing failed");
+
+ CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+ return false;
+ }
+
+ // Perform the remaining iteration
+ while (--iter > 0)
+ {
+ if (!hash->hashInit() ||
+ !hash->hashUpdate(intermediate) ||
+ !hash->hashFinal(intermediate))
+ {
+ ERROR_MSG("Hashing failed");
+
+ CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+ return false;
+ }
+ }
+
+ // Create the AES key instance
+ *ppKey = new AESKey(256);
+ (*ppKey)->setKeyBits(intermediate);
+
+ // Release the hash instance
+ CryptoFactory::i()->recycleHashAlgorithm(hash);
+
+ return true;
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/RFC4880.h b/SoftHSMv2/src/lib/data_mgr/RFC4880.h
new file mode 100644
index 0000000..7967ef6
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/RFC4880.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.
+ */
+
+/*****************************************************************************
+ RFC4880.h
+
+ Implements a secure password-based key derivation scheme. It is not a generic
+ implementation of the RFC but only generates 256-bit AES keys according to
+ the "iterated and salted" scheme.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RFC4880_H
+#define _SOFTHSM_V2_RFC4880_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "log.h"
+#include "AESKey.h"
+
+// This define sets the base PBE iteration count; the lowest byte of the salt is added
+// to this value as a form of jitter
+#define PBE_ITERATION_BASE_COUNT 1500
+
+namespace RFC4880
+{
+ // This function derives a 256-bit AES key from the supplied password data
+ bool PBEDeriveKey(const ByteString& password, ByteString& salt, AESKey** ppKey);
+}
+
+#endif // !_SOFTHSM_V2_RFC4880_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/SecureAllocator.h b/SoftHSMv2/src/lib/data_mgr/SecureAllocator.h
new file mode 100644
index 0000000..71dc80c
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/SecureAllocator.h
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SecureAllocator.h
+
+ Implements a template class for a secure C++ allocator. The allocator will
+ zero all the memory it allocates before releasing it to ensure that the
+ data stored in the memory is destroyed properly to minimise the risk of
+ obtaining sensitive data from memory
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SECUREALLOCATOR_H
+#define _SOFTHSM_V2_SECUREALLOCATOR_H
+
+#include <limits>
+#include <stdlib.h>
+#include <string.h>
+#if defined(SENSITIVE_NON_PAGED) && !defined(_WIN32)
+#include <sys/mman.h>
+#endif // SENSITIVE_NON_PAGED
+#include "config.h"
+#include "log.h"
+#include "SecureMemoryRegistry.h"
+
+template<class T> class SecureAllocator
+{
+public:
+ // Member types
+ typedef T value_type;
+ typedef T* pointer;
+ typedef T& reference;
+ typedef const T* const_pointer;
+ typedef const T& const_reference;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+ // Rebind to another type
+ template<class U> struct rebind
+ {
+ typedef SecureAllocator<U> other;
+ };
+
+ // Constructor
+ inline SecureAllocator() { }
+
+ inline SecureAllocator(const SecureAllocator&) { }
+
+ template<class U> SecureAllocator(const SecureAllocator<U>&) { }
+
+ // Destructor
+ inline virtual ~SecureAllocator() { }
+
+ // Return the maximum allocation size
+ size_type max_size() const
+ {
+ return std::numeric_limits<std::size_t>::max() / sizeof(T);
+ }
+
+ // Return the address of values
+ inline pointer address(reference value) const
+ {
+ return &value;
+ }
+
+ inline const_pointer address(const_reference value) const
+ {
+ return &value;
+ }
+
+ // Allocate n elements of type T
+ inline pointer allocate(size_type n, const void* = NULL)
+ {
+#ifdef SENSITIVE_NON_PAGED
+ // Allocate memory on a page boundary
+#ifndef _WIN32
+ pointer r = (pointer) valloc(n * sizeof(T));
+#else
+ pointer r = (pointer) VirtualAlloc(NULL, n * sizeof(T), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+#endif
+
+ if (r == NULL)
+ {
+ ERROR_MSG("Out of memory");
+
+ return NULL;
+ }
+
+ // Lock the memory so it doesn't get swapped out
+#ifndef _WIN32
+ if (mlock((const void*) r, n * sizeof(T)) != 0)
+#else
+ if (VirtualLock((const void*) r, n * sizeof(T)) == 0)
+#endif
+ {
+ ERROR_MSG("Could not allocate non-paged memory for secure storage");
+
+ // Hmmm... best to not return any allocated space in this case
+#ifndef _WIN32
+ free(r);
+#else
+ VirtualFree((const void*) r, MEM_RELEASE);
+#endif
+
+ return NULL;
+ }
+
+ // Register the memory in the secure memory registry
+ SecureMemoryRegistry::i()->add(r, n * sizeof(T));
+
+ return r;
+#else
+ pointer r = (pointer)(::operator new(n * sizeof(T)));
+
+ if (r == NULL)
+ {
+ ERROR_MSG("Out of memory");
+
+ return NULL;
+ }
+
+ // Register the memory in the secure memory registry
+ SecureMemoryRegistry::i()->add(r, n * sizeof(T));
+
+ return r;
+#endif // SENSITIVE_NON_PAGED
+ }
+
+ // Deallocate n elements of type T
+ inline void deallocate(pointer p, size_type n)
+ {
+#ifdef PARANOID
+ // First toggle all bits on
+ memset(p, 0xFF, n * sizeof(T));
+#endif // PARANOID
+
+ // Toggle all bits off
+ memset(p, 0x00, n * sizeof(T));
+
+ // Unregister the memory from the secure memory registry
+ SecureMemoryRegistry::i()->remove(p);
+
+#ifdef SENSITIVE_NON_PAGED
+#ifndef _WIN32
+ munlock((const void*) p, n * sizeof(T));
+#else
+ VirtualUnlock((const void*) p, n * sizeof(T));
+#endif
+
+#ifndef _WIN32
+ free(p);
+#else
+ VirtualFree((const void*) r, MEM_RELEASE);
+#endif
+#else
+ // Release the memory
+ ::operator delete((void*) p);
+#endif // SENSITIVE_NON_PAGED
+ }
+
+ // Initialise allocate storage with a value
+ void construct(pointer p, const T& value)
+ {
+ new((void*) p)T(value);
+ }
+
+ // Destroy elements of initialised storage
+ void destroy(pointer p)
+ {
+ // Call destructor
+ p->~T();
+ }
+
+ // Comparison operators
+ inline bool operator==(SecureAllocator const&) const { return true; }
+ inline bool operator!=(SecureAllocator const&) const { return false; }
+};
+
+#endif // !_SOFTHSM_V2_SECUREALLOCATOR_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp
new file mode 100644
index 0000000..987e76b
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.cpp
@@ -0,0 +1,537 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SecureDataManager.cpp
+
+ The secure data manager main class. Every token instance has a secure data
+ manager instance member that is used to decrypt and encrypt sensitive object
+ attributes such as key material. The secure data manager maintains a key blob
+ containing a 256-bit AES key that is used in this decryption and encryption
+ process. The key blob itself is encrypted using a PBE derived key that is
+ derived from the user PIN and a PBE key that is derived from the SO PIN. It
+ is up to the token to enforce access control based on which user is logged
+ in; authentication using the SO PIN is required to be able to change the
+ user PIN. The master key that is used to decrypt/encrypt sensitive attributes
+ is stored in memory under a mask that is changed every time the key is used.
+ *****************************************************************************/
+
+#include "config.h"
+#include "SecureDataManager.h"
+#include "CryptoFactory.h"
+#include "AESKey.h"
+#include "SymmetricAlgorithm.h"
+#include "RFC4880.h"
+
+// Constructors
+
+// Initialise the object; called by all constructors
+void SecureDataManager::initObject()
+{
+ // Get an RNG instance
+ rng = CryptoFactory::i()->getRNG();
+
+ // Get an AES implementation
+ aes = CryptoFactory::i()->getSymmetricAlgorithm(SymAlgo::AES);
+
+ // Initialise masking data
+ mask = new ByteString();
+
+ rng->generateRandom(*mask, 32);
+
+ // Set the initial login state
+ soLoggedIn = userLoggedIn = false;
+
+ // Set the magic
+ magic = ByteString("524A52"); // RJR
+
+ // Get a mutex
+ dataMgrMutex = MutexFactory::i()->getMutex();
+}
+
+// Constructs a new SecureDataManager for a blank token; actual
+// initialisation is done by setting the SO PIN
+SecureDataManager::SecureDataManager()
+{
+ initObject();
+}
+
+// Constructs a SecureDataManager using the specified key blob
+SecureDataManager::SecureDataManager(const ByteString& soPINBlob, const ByteString& userPINBlob)
+{
+ initObject();
+
+ // De-serialise the key blob
+ soEncryptedKey = soPINBlob;
+ userEncryptedKey = userPINBlob;
+}
+
+// Destructor
+SecureDataManager::~SecureDataManager()
+{
+ // Recycle the AES instance
+ CryptoFactory::i()->recycleSymmetricAlgorithm(aes);
+
+ // Clean up the mask
+ delete mask;
+
+ MutexFactory::i()->recycleMutex(dataMgrMutex);
+}
+
+// Generic function for creating an encrypted version of the key from the specified passphrase
+bool SecureDataManager::pbeEncryptKey(const ByteString& passphrase, ByteString& encryptedKey)
+{
+ // Generate salt
+ ByteString salt;
+
+ if (!rng->generateRandom(salt, 8)) return false;
+
+ // Derive the key using RFC4880 PBE
+ AESKey* pbeKey = NULL;
+
+ if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey))
+ {
+ return false;
+ }
+
+ // Add the salt
+ encryptedKey.wipe();
+ encryptedKey += salt;
+
+ // Generate random IV
+ ByteString IV;
+
+ if (!rng->generateRandom(IV, aes->getBlockSize())) return false;
+
+ // Add the IV
+ encryptedKey += IV;
+
+ // Encrypt the data
+ ByteString block;
+
+ if (!aes->encryptInit(pbeKey, SymMode::CBC, IV))
+ {
+ delete pbeKey;
+
+ return false;
+ }
+
+ // First, add the magic
+ if (!aes->encryptUpdate(magic, block))
+ {
+ delete pbeKey;
+
+ return false;
+ }
+
+ encryptedKey += block;
+
+ // Then, add the key itself
+ ByteString key;
+
+ {
+ MutexLocker lock(dataMgrMutex);
+
+ unmask(key);
+
+ bool rv = aes->encryptUpdate(key, block);
+
+ remask(key);
+
+ if (!rv)
+ {
+ delete pbeKey;
+
+ return false;
+ }
+ }
+
+ encryptedKey += block;
+
+ // And finalise encryption
+ if (!aes->encryptFinal(block))
+ {
+ delete pbeKey;
+
+ return false;
+ }
+
+ encryptedKey += block;
+
+ delete pbeKey;
+
+ return true;
+}
+
+// Set the SO PIN (requires either a blank SecureDataManager or the
+// SO to have logged in previously)
+bool SecureDataManager::setSOPIN(const ByteString& soPIN)
+{
+ // Check the new PIN
+ if (soPIN.size() == 0)
+ {
+ DEBUG_MSG("Zero length PIN specified");
+
+ return false;
+ }
+
+ // Check if the SO needs to be logged in
+ if ((soEncryptedKey.size() > 0) && !soLoggedIn)
+ {
+ DEBUG_MSG("SO must be logged in to change the SO PIN");
+
+ return false;
+ }
+
+ // If no SO PIN was set, then this is a SecureDataManager for a blank token. This
+ // means a new key has to be generated
+ if (soEncryptedKey.size() == 0)
+ {
+ ByteString key;
+
+ rng->generateRandom(key, 32);
+
+ remask(key);
+ }
+
+ return pbeEncryptKey(soPIN, soEncryptedKey);
+}
+
+// Set the user PIN (requires either the SO or the user to have logged
+// in previously)
+bool SecureDataManager::setUserPIN(const ByteString& userPIN)
+{
+ // Check if the SO or the user is logged in
+ if (!soLoggedIn && !userLoggedIn)
+ {
+ DEBUG_MSG("Must be logged in to change the user PIN");
+
+ return false;
+ }
+
+ // Check the new PIN
+ if (userPIN.size() == 0)
+ {
+ DEBUG_MSG("Zero length PIN specified");
+
+ return false;
+ }
+
+ return pbeEncryptKey(userPIN, userEncryptedKey);
+}
+
+// Generic login function
+bool SecureDataManager::login(const ByteString& passphrase, const ByteString& encryptedKey)
+{
+ // Log out first
+ this->logout();
+
+ // First, take the salt from the encrypted key
+ ByteString salt = encryptedKey.substr(0,8);
+
+ // Then, take the IV from the encrypted key
+ ByteString IV = encryptedKey.substr(8, aes->getBlockSize());
+
+ // Now, take the encrypted data from the encrypted key
+ ByteString encryptedKeyData = encryptedKey.substr(8 + aes->getBlockSize());
+
+ // Derive the PBE key
+ AESKey* pbeKey = NULL;
+
+ if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey))
+ {
+ return false;
+ }
+
+ // Decrypt the key data
+ ByteString decryptedKeyData;
+ ByteString finalBlock;
+
+ // NOTE: The login will fail here if incorrect passphrase is supplied
+ if (!aes->decryptInit(pbeKey, SymMode::CBC, IV) ||
+ !aes->decryptUpdate(encryptedKeyData, decryptedKeyData) ||
+ !aes->decryptFinal(finalBlock))
+ {
+ delete pbeKey;
+
+ return false;
+ }
+
+ delete pbeKey;
+
+ decryptedKeyData += finalBlock;
+
+ // Check the magic
+ if (decryptedKeyData.substr(0, 3) != magic)
+ {
+ // The passphrase was incorrect
+ DEBUG_MSG("Incorrect passphrase supplied");
+
+ return false;
+ }
+
+ // Strip off the magic
+ ByteString key = decryptedKeyData.substr(3);
+
+ // And mask the key
+ decryptedKeyData.wipe();
+
+ MutexLocker lock(dataMgrMutex);
+ remask(key);
+
+ return true;
+}
+
+// Log in using the SO PIN
+bool SecureDataManager::loginSO(const ByteString& soPIN)
+{
+ return (soLoggedIn = login(soPIN, soEncryptedKey));
+}
+
+// Log in using the user PIN
+bool SecureDataManager::loginUser(const ByteString& userPIN)
+{
+ return (userLoggedIn = login(userPIN, userEncryptedKey));
+}
+
+// Generic re-authentication function
+bool SecureDataManager::reAuthenticate(const ByteString& passphrase, const ByteString& encryptedKey)
+{
+ // First, take the salt from the encrypted key
+ ByteString salt = encryptedKey.substr(0,8);
+
+ // Then, take the IV from the encrypted key
+ ByteString IV = encryptedKey.substr(8, aes->getBlockSize());
+
+ // Now, take the encrypted data from the encrypted key
+ ByteString encryptedKeyData = encryptedKey.substr(8 + aes->getBlockSize());
+
+ // Derive the PBE key
+ AESKey* pbeKey = NULL;
+
+ if (!RFC4880::PBEDeriveKey(passphrase, salt, &pbeKey))
+ {
+ return false;
+ }
+
+ // Decrypt the key data
+ ByteString decryptedKeyData;
+ ByteString finalBlock;
+
+ // NOTE: The login will fail here if incorrect passphrase is supplied
+ if (!aes->decryptInit(pbeKey, SymMode::CBC, IV) ||
+ !aes->decryptUpdate(encryptedKeyData, decryptedKeyData) ||
+ !aes->decryptFinal(finalBlock))
+ {
+ delete pbeKey;
+
+ return false;
+ }
+
+ delete pbeKey;
+
+ decryptedKeyData += finalBlock;
+
+ // Check the magic
+ if (decryptedKeyData.substr(0, 3) != magic)
+ {
+ // The passphrase was incorrect
+ DEBUG_MSG("Incorrect passphrase supplied");
+
+ return false;
+ }
+
+ // And mask the key
+ decryptedKeyData.wipe();
+
+ return true;
+}
+
+// Re-authenticate the SO
+bool SecureDataManager::reAuthenticateSO(const ByteString& soPIN)
+{
+ return reAuthenticate(soPIN, soEncryptedKey);
+}
+
+// Re-authenticate the user
+bool SecureDataManager::reAuthenticateUser(const ByteString& userPIN)
+{
+ return reAuthenticate(userPIN, userEncryptedKey);
+}
+
+// Log out
+void SecureDataManager::logout()
+{
+ MutexLocker lock(dataMgrMutex);
+
+ // Clear the logged in state
+ soLoggedIn = userLoggedIn = false;
+
+ // Clear the masked key
+ maskedKey.wipe();
+}
+
+// Decrypt the supplied data
+bool SecureDataManager::decrypt(const ByteString& encrypted, ByteString& plaintext)
+{
+ // Check the object logged in state
+ if ((!userLoggedIn && !soLoggedIn) || (maskedKey.size() != 32))
+ {
+ return false;
+ }
+
+ // Do not attempt decryption of empty byte strings
+ if (encrypted.size() == 0)
+ {
+ plaintext = ByteString("");
+ return true;
+ }
+
+ AESKey theKey(256);
+ ByteString unmaskedKey;
+
+ {
+ MutexLocker lock(dataMgrMutex);
+
+ unmask(unmaskedKey);
+
+ theKey.setKeyBits(unmaskedKey);
+
+ remask(unmaskedKey);
+ }
+
+ // Take the IV from the input data
+ ByteString IV = encrypted.substr(0, aes->getBlockSize());
+
+ if (IV.size() != aes->getBlockSize())
+ {
+ ERROR_MSG("Invalid IV in encrypted data");
+
+ return false;
+ }
+
+ ByteString finalBlock;
+
+ if (!aes->decryptInit(&theKey, SymMode::CBC, IV) ||
+ !aes->decryptUpdate(encrypted.substr(aes->getBlockSize()), plaintext) ||
+ !aes->decryptFinal(finalBlock))
+ {
+ return false;
+ }
+
+ plaintext += finalBlock;
+
+ return true;
+}
+
+// Encrypt the supplied data
+bool SecureDataManager::encrypt(const ByteString& plaintext, ByteString& encrypted)
+{
+ // Check the object logged in state
+ if ((!userLoggedIn && !soLoggedIn) || (maskedKey.size() != 32))
+ {
+ return false;
+ }
+
+ AESKey theKey(256);
+ ByteString unmaskedKey;
+
+ {
+ MutexLocker lock(dataMgrMutex);
+
+ unmask(unmaskedKey);
+
+ theKey.setKeyBits(unmaskedKey);
+
+ remask(unmaskedKey);
+ }
+
+ // Wipe encrypted data block
+ encrypted.wipe();
+
+ // Generate random IV
+ ByteString IV;
+
+ if (!rng->generateRandom(IV, aes->getBlockSize())) return false;
+
+ ByteString finalBlock;
+
+ if (!aes->encryptInit(&theKey, SymMode::CBC, IV) ||
+ !aes->encryptUpdate(plaintext, encrypted) ||
+ !aes->encryptFinal(finalBlock))
+ {
+ return false;
+ }
+
+ encrypted += finalBlock;
+
+ // Add IV to output data
+ encrypted = IV + encrypted;
+
+ return true;
+}
+
+// Returns the key blob for the SO PIN
+ByteString SecureDataManager::getSOPINBlob()
+{
+ return soEncryptedKey;
+}
+
+// Returns the key blob for the user PIN
+ByteString SecureDataManager::getUserPINBlob()
+{
+ return userEncryptedKey;
+}
+
+// Unmask the key
+void SecureDataManager::unmask(ByteString& key)
+{
+ key = maskedKey;
+ key ^= *mask;
+}
+
+// Remask the key
+void SecureDataManager::remask(ByteString& key)
+{
+ // Generate a new mask
+ rng->generateRandom(*mask, 32);
+
+ key ^= *mask;
+ maskedKey = key;
+}
+
+// Check if the SO is logged in
+bool SecureDataManager::isSOLoggedIn()
+{
+ return soLoggedIn;
+}
+
+// Check if the user is logged in
+bool SecureDataManager::isUserLoggedIn()
+{
+ return userLoggedIn;
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/SecureDataManager.h b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.h
new file mode 100644
index 0000000..93d99bc
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/SecureDataManager.h
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SecureDataManager.h
+
+ The secure data manager main class. Every token instance has a secure data
+ manager instance member that is used to decrypt and encrypt sensitive object
+ attributes such as key material. The secure data manager maintains a key blob
+ containing a 256-bit AES key that is used in this decryption and encryption
+ process. The key blob itself is encrypted using a PBE derived key that is
+ derived from the user PIN and a PBE key that is derived from the SO PIN. It
+ is up to the token to enforce access control based on which user is logged
+ in; authentication using the SO PIN is required to be able to change the
+ user PIN. The master key that is used to decrypt/encrypt sensitive attributes
+ is stored in memory under a mask that is changed every time the key is used.
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SECUREDATAMANAGER_H
+#define _SOFTHSM_V2_SECUREDATAMANAGER_H
+
+#include "config.h"
+#include "ByteString.h"
+#include "log.h"
+#include "AESKey.h"
+#include "RNG.h"
+#include "SymmetricAlgorithm.h"
+#include "MutexFactory.h"
+
+class SecureDataManager
+{
+public:
+ // Constructors
+
+ // Constructs a new SecureDataManager for a blank token; actual
+ // initialisation is done by setting the SO PIN
+ SecureDataManager();
+
+ // Constructs a SecureDataManager using the specified SO PIN and user PIN
+ SecureDataManager(const ByteString& soPINBlob, const ByteString& userPINBlob);
+
+ // Destructor
+ virtual ~SecureDataManager();
+
+ // Set the SO PIN (requires either a blank SecureDataManager or the
+ // SO to have logged in previously)
+ bool setSOPIN(const ByteString& soPIN);
+
+ // Set the user PIN (requires either the SO or the user to have logged
+ // in previously)
+ bool setUserPIN(const ByteString& userPIN);
+
+ // Log in using the SO PIN
+ bool loginSO(const ByteString& soPIN);
+ bool isSOLoggedIn();
+
+ // Log in using the user PIN
+ bool loginUser(const ByteString& userPIN);
+ bool isUserLoggedIn();
+
+ // Re-authentication
+ bool reAuthenticateSO(const ByteString& soPIN);
+ bool reAuthenticateUser(const ByteString& userPIN);
+
+ // Log out
+ void logout();
+
+ // Decrypt the supplied data
+ bool decrypt(const ByteString& encrypted, ByteString& plaintext);
+
+ // Encrypt the supplied data
+ bool encrypt(const ByteString& plaintext, ByteString& encrypted);
+
+ // Returns the key blob for the SO PIN
+ ByteString getSOPINBlob();
+
+ // Returns the key blob for the user PIN
+ ByteString getUserPINBlob();
+
+private:
+ // Initialise the object
+ void initObject();
+
+ // Generic login function
+ bool login(const ByteString& passphrase, const ByteString& encryptedKey);
+
+ // Generic re-authentication function
+ bool reAuthenticate(const ByteString& passphrase, const ByteString& encryptedKey);
+
+ // Generic function for creating an encrypted version of the key from the specified passphrase
+ bool pbeEncryptKey(const ByteString& passphrase, ByteString& encryptedKey);
+
+ // Unmask the key
+ void unmask(ByteString& key);
+
+ // Remask the key
+ void remask(ByteString& key);
+
+ // The user PIN encrypted key
+ ByteString userEncryptedKey;
+
+ // The SO PIN encrypted key
+ ByteString soEncryptedKey;
+
+ // Which users are logged in
+ bool soLoggedIn;
+ bool userLoggedIn;
+
+ // The masked version of the actual key
+ ByteString maskedKey;
+
+ // The "magic" data used to detect if a PIN was likely to be correct
+ ByteString magic;
+
+ // The mask; this is not a stack member but a heap member. This
+ // hopefully ensures that the mask ends up in a memory location
+ // that is not logically linked to the masked key
+ ByteString* mask;
+
+ // Random number generator instance
+ RNG* rng;
+
+ // AES instance
+ SymmetricAlgorithm* aes;
+
+ // Mutex
+ Mutex* dataMgrMutex;
+};
+
+#endif // !_SOFTHSM_V2_SECUREDATAMANAGER_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp
new file mode 100644
index 0000000..57de156
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SecureMemoryRegistry.cpp
+
+ Implements a singleton class that keeps track of all securely allocated
+ memory. This registry can be used to wipe securely allocated memory in case
+ of a fatal exception
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "log.h"
+#include "SecureMemoryRegistry.h"
+
+// Constructor
+SecureMemoryRegistry::SecureMemoryRegistry()
+{
+ SecMemRegistryMutex = MutexFactory::i()->getMutex();
+}
+
+// Destructor
+SecureMemoryRegistry::~SecureMemoryRegistry()
+{
+ if (!registry.empty())
+ {
+ ERROR_MSG("SecureMemoryRegistry is not empty: leak!");
+ }
+ MutexFactory::i()->recycleMutex(SecMemRegistryMutex);
+}
+
+// Return the one-and-only instance
+SecureMemoryRegistry* SecureMemoryRegistry::i()
+{
+ if (instance.get() == NULL)
+ {
+ instance.reset(new SecureMemoryRegistry());
+
+ if (instance.get() == NULL)
+ {
+ // This is very bad!
+ ERROR_MSG("failed to instantiate SecureMemoryRegistry");
+
+ }
+ }
+
+ return instance.get();
+}
+
+// This will destroy the one-and-only instance.
+void SecureMemoryRegistry::reset()
+{
+ instance.reset();
+}
+
+// Register a block of memory
+void SecureMemoryRegistry::add(void* pointer, size_t blocksize)
+{
+ MutexLocker lock(SecMemRegistryMutex);
+
+ registry[pointer] = blocksize;
+
+ //DEBUG_MSG("Registered block of %d bytes at 0x%x", blocksize, pointer);
+}
+
+// Unregister a block of memory
+size_t SecureMemoryRegistry::remove(void* pointer)
+{
+ //DEBUG_MSG("Unregistered block of %d bytes at 0x%x", registry[pointer], pointer);
+
+ MutexLocker lock(SecMemRegistryMutex);
+
+ size_t rv = registry[pointer];
+
+ registry.erase(pointer);
+
+ return rv;
+}
+
+// Wipe all registered blocks of memory
+void SecureMemoryRegistry::wipe()
+{
+ MutexLocker lock(SecMemRegistryMutex);
+
+ // Be very careful in this method to catch any weird exceptions that
+ // may occur since if we're in this method it means something has already
+ // gone pear shaped once before and we're exiting on a fatal exception
+ try
+ {
+ for (std::map<void*, size_t>::iterator i = registry.begin(); i != registry.end(); i++)
+ {
+ try
+ {
+ DEBUG_MSG("Wiping block of %d bytes at 0x%x", i->second, i->first);
+ }
+ catch (...)
+ {
+ }
+
+ try
+ {
+ #ifdef PARANOID
+ memset(i->first, 0xFF, i->second);
+ #endif // PARANOID
+ memset(i->first, 0x00, i->second);
+ }
+ catch (...)
+ {
+ ERROR_MSG("Failed to wipe block of %d bytes at 0x%x", i->second, i->first);
+ }
+ }
+ }
+ catch (...)
+ {
+ ERROR_MSG("Failed to enumerate the secure memory registry");
+ }
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h
new file mode 100644
index 0000000..6c73369
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/SecureMemoryRegistry.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SecureMemoryRegistry.h
+
+ Implements a singleton class that keeps track of all securely allocated
+ memory. This registry can be used to wipe securely allocated memory in case
+ of a fatal exception
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SECUREMEMORYREGISTRY_H
+#define _SOFTHSM_V2_SECUREMEMORYREGISTRY_H
+
+#include <stdlib.h>
+#include <map>
+#include <memory>
+#include "MutexFactory.h"
+
+class SecureMemoryRegistry
+{
+public:
+ SecureMemoryRegistry();
+
+ virtual ~SecureMemoryRegistry();
+
+ static SecureMemoryRegistry* i();
+
+ static void reset();
+
+ void add(void* pointer, size_t blocksize);
+
+ size_t remove(void* pointer);
+
+ void wipe();
+
+private:
+#ifdef HAVE_CXX11
+ static std::unique_ptr<SecureMemoryRegistry> instance;
+#else
+ static std::auto_ptr<SecureMemoryRegistry> instance;
+#endif
+
+ std::map<void*, size_t> registry;
+
+ Mutex* SecMemRegistryMutex;
+};
+
+#endif // !_SOFTHSM_V2_SECUREMEMORYREGISTRY_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/salloc.cpp b/SoftHSMv2/src/lib/data_mgr/salloc.cpp
new file mode 100644
index 0000000..0bd4238
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/salloc.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ salloc.cpp
+
+ Contains an implementation of malloc that allocates memory securely
+ *****************************************************************************/
+
+#include "config.h"
+#include "log.h"
+#include "salloc.h"
+#include <limits>
+#if defined(SENSITIVE_NON_PAGED) && !defined(_WIN32)
+#include <sys/mman.h>
+#endif // SENSITIVE_NON_PAGED
+#include <string.h>
+#include "SecureMemoryRegistry.h"
+
+// Allocate memory
+void* salloc(size_t len)
+{
+#ifdef SENSITIVE_NON_PAGED
+ // Allocate memory on a page boundary
+#ifndef _WIN32
+ void* ptr = (void*) valloc(len);
+#else
+ pointer r = (pointer) VirtualAlloc(NULL, n * sizeof(T), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+#endif
+
+ if (ptr == NULL)
+ {
+ ERROR_MSG("Out of memory");
+
+ return NULL;
+ }
+
+ // Lock the memory so it doesn't get swapped out
+#ifndef _WIN32
+ if (mlock((const void*) ptr, len) != 0)
+#else
+ if (VirtualLock((const void*) r, n * sizeof(T)) == 0)
+#endif
+ {
+ ERROR_MSG("Could not allocate non-paged memory for secure storage");
+
+ // Hmmm... best to not return any allocated space in this case
+#ifndef _WIN32
+ free(ptr);
+#else
+ VirtualFree((const void*) pre, MEM_RELEASE);
+#endif
+
+ return NULL;
+ }
+
+ // Register the memory in the secure memory registry
+ SecureMemoryRegistry::i()->add(ptr, len);
+
+ return ptr;
+#else
+ void* ptr = (void*) malloc(len);
+
+ if (ptr == NULL)
+ {
+ ERROR_MSG("Out of memory");
+
+ return NULL;
+ }
+
+ // Register the memory in the secure memory registry
+ SecureMemoryRegistry::i()->add(ptr, len);
+
+ return ptr;
+#endif // SENSITIVE_NON_PAGED
+}
+
+// Free memory
+void sfree(void* ptr)
+{
+ // Unregister the memory from the secure memory registry
+ size_t len = SecureMemoryRegistry::i()->remove(ptr);
+
+#ifdef PARANOID
+ // First toggle all bits on
+ memset(ptr, 0xFF, len);
+#endif // PARANOID
+
+ // Toggle all bits off
+ memset(ptr, 0x00, len);
+
+#ifdef SENSITIVE_NON_PAGED
+#ifndef _WIN32
+ munlock((const void*) ptr, len);
+#else
+ VirtualFree((const void*) pre, MEM_RELEASE);
+#endif
+
+#endif // SENSITIVE_NON_PAGED
+
+ free(ptr);
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/salloc.h b/SoftHSMv2/src/lib/data_mgr/salloc.h
new file mode 100644
index 0000000..cfd92fe
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/salloc.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.
+ */
+
+/*****************************************************************************
+ salloc.h
+
+ Contains an implementation of malloc that allocates memory securely
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SALLOC_H
+#define _SOFTHSM_V2_SALLOC_H
+
+#include <stdlib.h>
+#include "config.h"
+#include "log.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* Allocate memory */
+void* salloc(size_t len);
+
+/* Free memory */
+void sfree(void* ptr);
+
+#if defined (__cplusplus)
+}
+#endif
+
+#endif /* !_SOFTHSM_V2_SALLOC_H */
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp
new file mode 100644
index 0000000..1c635a4
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.cpp
@@ -0,0 +1,356 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ByteStringTests.cpp
+
+ Contains test cases to test the ByteString class
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <string>
+#include "ByteStringTests.h"
+#include "ByteString.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ByteStringTests);
+
+void ByteStringTests::setUp()
+{
+}
+
+void ByteStringTests::tearDown()
+{
+ fflush(stdout);
+}
+
+void ByteStringTests::testIntegrity()
+{
+ unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
+
+ ByteString b(testData, sizeof(testData));
+
+ // Test if the right data is returned
+ CPPUNIT_ASSERT(memcmp(testData, b.byte_str(), sizeof(testData)) == 0);
+
+ // Test size
+ CPPUNIT_ASSERT(b.size() == sizeof(testData));
+
+ // Test the copy constructor
+ ByteString b2(b);
+
+ // Test using comparison operator
+ CPPUNIT_ASSERT(b == b2);
+
+ // Test using memcmp
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), b2.byte_str(), b.size()) == 0);
+
+ // Modify the copied version and test again
+ b2[1] = 0x20;
+
+ // Test using comparison operator
+ CPPUNIT_ASSERT(b != b2);
+
+ // Test using memcmp directly
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), b2.byte_str(), b.size()) != 0);
+
+ // Verify that b was not affected
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), testData, sizeof(testData)) == 0);
+
+ // Modify the source data and check if the array operator has functioned correctly
+ testData[1] = 0x20;
+
+ // Test if the right data is in b2
+ CPPUNIT_ASSERT(memcmp(b2.byte_str(), testData, sizeof(testData)) == 0);
+}
+
+void ByteStringTests::testAppend()
+{
+ unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
+
+ ByteString b;
+ ByteString b1(testData, sizeof(testData));
+
+ // Test that b is empty and b1 is not
+ CPPUNIT_ASSERT((b.size() == 0) && (b1.size() == sizeof(testData)));
+
+ // Append 1 byte to b
+ b += 0x01;
+
+ // Check the contents of b
+ CPPUNIT_ASSERT(b.size() == 1);
+ CPPUNIT_ASSERT(b[0] == 0x01);
+
+ // Append another byte to b
+ b += 0x02;
+
+ // Check the contents of b
+ CPPUNIT_ASSERT(b.size() == 2);
+ CPPUNIT_ASSERT((b[0] == 0x01) && (b[1] == 0x02));
+
+ // Append b1 to b
+ b += b1;
+
+ // Check the contents of b
+ CPPUNIT_ASSERT(b.size() == 2 + sizeof(testData));
+ CPPUNIT_ASSERT((b[0] == 0x01) && (b[1] == 0x02));
+ CPPUNIT_ASSERT(memcmp(&b[2], testData, sizeof(testData)) == 0);
+
+ // Append b to b
+ b += b;
+
+ // Check the contents of b
+ CPPUNIT_ASSERT(b.size() == 2 * (2 + sizeof(testData)));
+ CPPUNIT_ASSERT((b[0] == 0x01) && (b[1] == 0x02) &&
+ (b[(2 + sizeof(testData)) + 0] == 0x01) &&
+ (b[(2 + sizeof(testData)) + 1] == 0x02));
+ CPPUNIT_ASSERT((memcmp(&b[2], testData, sizeof(testData)) == 0) &&
+ (memcmp(&b[2 + 2 + sizeof(testData)], testData, sizeof(testData)) == 0));
+}
+
+void ByteStringTests::testSubstr()
+{
+ unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
+
+ ByteString b;
+ ByteString b1(testData, sizeof(testData));
+
+ // Take a substring
+ b = b1.substr(8, 4);
+
+ // Check b
+ CPPUNIT_ASSERT(b.size() == 4);
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), &testData[8], 4) == 0);
+
+ // Take another substring
+ b = b1.substr(8);
+
+ // Check b
+ CPPUNIT_ASSERT(b.size() == 8);
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), &testData[8], 8) == 0);
+
+ // Two substrings added should yield the original string
+ b = b1.substr(0, 8) + b1.substr(8);
+
+ // Check b
+ CPPUNIT_ASSERT(b.size() == sizeof(testData));
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), testData, sizeof(testData)) == 0);
+}
+
+void ByteStringTests::testFromHexStr()
+{
+ unsigned char testData[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
+
+ ByteString b("0102030405060708090a0b0c0d0e0f10");
+ ByteString b1("0102030405060708090A0B0C0D0E0F10");
+
+ CPPUNIT_ASSERT(memcmp(b.byte_str(), testData, sizeof(testData)) == 0);
+ CPPUNIT_ASSERT(memcmp(b1.byte_str(), testData, sizeof(testData)) == 0);
+}
+
+void ByteStringTests::testXOR()
+{
+ unsigned char left[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+ unsigned char right[] = { 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10 };
+ unsigned char xorred[] = { 0x81, 0x72, 0x63, 0x54, 0x45, 0x36, 0x27, 0x18 };
+
+ ByteString l(left, 8);
+ ByteString r(right, 8);
+ ByteString x(xorred, 8);
+ ByteString xed;
+
+ xed = l ^ r;
+
+ CPPUNIT_ASSERT(xed == x);
+
+ ByteString l1(left, 8);
+ ByteString r1(right, 8);
+
+ l1 ^= r1;
+
+ CPPUNIT_ASSERT(l1 == x);
+
+ l1 ^= l;
+
+ CPPUNIT_ASSERT(l1 == r);
+
+ ByteString l_(left, 7);
+
+ xed = l_ ^ r;
+
+ CPPUNIT_ASSERT((xed.size() == 7) && (xed == x.substr(0, 7)));
+
+ ByteString r_(right, 7);
+
+ xed = l ^ r_;
+
+ CPPUNIT_ASSERT((xed.size() == 7) && (xed == x.substr(0, 7)));
+
+ ByteString l1_(left, 8);
+
+ l1_ ^= r_;
+
+ CPPUNIT_ASSERT((l1.size() == 8) && (l1_.substr(0, 7) == x.substr(0,7)) && (l1_[7] == l[7]));
+
+ ByteString l1__(left, 7);
+
+ l1__ ^= r;
+
+ CPPUNIT_ASSERT((l1__ == x.substr(0,7)) && (l1__.size() == 7));
+}
+
+void ByteStringTests::testToHexStr()
+{
+ ByteString b("0102030405060708090A0B0C0D0E0F");
+ ByteString b1("DEADBEEF");
+ ByteString b2("deadC0FFEE");
+
+ std::string s = b.hex_str();
+ std::string s1 = b1.hex_str();
+ std::string s2 = b2.hex_str();
+
+ CPPUNIT_ASSERT(s.compare("0102030405060708090A0B0C0D0E0F") == 0);
+ CPPUNIT_ASSERT(s1.compare("DEADBEEF") == 0);
+ CPPUNIT_ASSERT(s2.compare("DEADC0FFEE") == 0);
+}
+
+void ByteStringTests::testLongValues()
+{
+ unsigned long ul1 = 0x00112233;
+ unsigned long ul2 = 0x10203040;
+ unsigned long ul3 = 0xF0E0D0C0;
+
+ ByteString b1(ul1);
+ ByteString b2(ul2);
+ ByteString b3(ul3);
+
+ CPPUNIT_ASSERT(b1 == ByteString("0000000000112233"));
+ CPPUNIT_ASSERT(b2 == ByteString("0000000010203040"));
+ CPPUNIT_ASSERT(b3 == ByteString("00000000F0E0D0C0"));
+
+ CPPUNIT_ASSERT(b1.long_val() == ul1);
+ CPPUNIT_ASSERT(b2.long_val() == ul2);
+ CPPUNIT_ASSERT(b3.long_val() == ul3);
+
+ ByteString concat = b1 + b2 + b3;
+
+ CPPUNIT_ASSERT(concat == ByteString("0000000000112233000000001020304000000000F0E0D0C0"));
+
+ unsigned long ulr1 = concat.firstLong();
+
+ CPPUNIT_ASSERT(ulr1 == ul1);
+ CPPUNIT_ASSERT(concat == ByteString("000000001020304000000000F0E0D0C0"));
+
+ unsigned long ulr2 = concat.firstLong();
+
+ CPPUNIT_ASSERT(ulr2 == ul2);
+ CPPUNIT_ASSERT(concat == ByteString("00000000F0E0D0C0"));
+
+ unsigned long ulr3 = concat.firstLong();
+
+ CPPUNIT_ASSERT(ulr3 == ul3);
+ CPPUNIT_ASSERT(concat.size() == 0);
+
+ ByteString b4("ABCDEF");
+
+ CPPUNIT_ASSERT(b4.long_val() == 0xABCDEF);
+ CPPUNIT_ASSERT(b4.size() == 3);
+ CPPUNIT_ASSERT(b4.firstLong() == 0xABCDEF);
+ CPPUNIT_ASSERT(b4.size() == 0);
+}
+
+void ByteStringTests::testSplitting()
+{
+ ByteString b("AABBCCDDEEFF112233445566");
+
+ ByteString b1 = b.split(6);
+
+ CPPUNIT_ASSERT(b == ByteString("112233445566"));
+ CPPUNIT_ASSERT(b1 == ByteString("AABBCCDDEEFF"));
+
+ ByteString b2 = b1.split(8);
+
+ CPPUNIT_ASSERT(b2 == ByteString("AABBCCDDEEFF"));
+ CPPUNIT_ASSERT(b1.size() == 0);
+}
+
+void ByteStringTests::testBits()
+{
+ ByteString b1("0");
+ ByteString b2("08");
+ ByteString b3("00FFFFF");
+ ByteString b4("123456");
+
+ CPPUNIT_ASSERT(b1.bits() == 0);
+ CPPUNIT_ASSERT(b2.bits() == 4);
+ CPPUNIT_ASSERT(b3.bits() == 20);
+ CPPUNIT_ASSERT(b4.bits() == 21);
+}
+
+void ByteStringTests::testSerialising()
+{
+ ByteString b1("AA11AA11AA11AA11AA11AA11AA11");
+ ByteString b2("BB22BB22BB22BB22BB22BB22");
+ ByteString b3("CC33CC33CC33CC33CC33CC33CC33CC33");
+
+ ByteString s1 = b1.serialise();
+
+ CPPUNIT_ASSERT(s1.size() == b1.size() + 8);
+
+ ByteString d1 = ByteString::chainDeserialise(s1);
+
+ CPPUNIT_ASSERT(s1.size() == 0);
+ CPPUNIT_ASSERT(d1 == b1);
+
+ ByteString s2 = b3.serialise() + b2.serialise() + b1.serialise();
+
+ CPPUNIT_ASSERT(s2.size() == b1.size() + b2.size() + b3.size() + (3*8));
+
+ d1 = ByteString::chainDeserialise(s2);
+
+ CPPUNIT_ASSERT(d1.size() == b3.size());
+ CPPUNIT_ASSERT(s2.size() == b1.size() + b2.size() + (2*8));
+
+ ByteString d2 = ByteString::chainDeserialise(s2);
+
+ CPPUNIT_ASSERT(d2.size() == b2.size());
+ CPPUNIT_ASSERT(s2.size() == b1.size() + 8);
+
+ ByteString d3 = ByteString::chainDeserialise(s2);
+
+ CPPUNIT_ASSERT(d3.size() == b1.size());
+ CPPUNIT_ASSERT(s2.size() == 0);
+
+ CPPUNIT_ASSERT(d1 == b3);
+ CPPUNIT_ASSERT(d2 == b2);
+ CPPUNIT_ASSERT(d3 == b1);
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h
new file mode 100644
index 0000000..b1dd967
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/ByteStringTests.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ ByteStringTests.h
+
+ Contains test cases to test the ByteString class
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_BYTESTRINGTESTS_H
+#define _SOFTHSM_V2_BYTESTRINGTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class ByteStringTests : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(ByteStringTests);
+ CPPUNIT_TEST(testIntegrity);
+ CPPUNIT_TEST(testAppend);
+ CPPUNIT_TEST(testSubstr);
+ CPPUNIT_TEST(testFromHexStr);
+ CPPUNIT_TEST(testXOR);
+ CPPUNIT_TEST(testToHexStr);
+ CPPUNIT_TEST(testLongValues);
+ CPPUNIT_TEST(testSplitting);
+ CPPUNIT_TEST(testBits);
+ CPPUNIT_TEST(testSerialising);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void testIntegrity();
+ void testAppend();
+ void testSubstr();
+ void testFromHexStr();
+ void testXOR();
+ void testToHexStr();
+ void testLongValues();
+ void testSplitting();
+ void testBits();
+ void testSerialising();
+
+ void setUp();
+ void tearDown();
+
+};
+
+#endif // !_SOFTHSM_V2_BYTESTRINGTESTS_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/Makefile.am b/SoftHSMv2/src/lib/data_mgr/test/Makefile.am
new file mode 100644
index 0000000..e1ebcdd
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/Makefile.am
@@ -0,0 +1,27 @@
+MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
+
+AM_CPPFLAGS = -I$(srcdir)/.. \
+ -I$(srcdir)/../.. \
+ -I$(srcdir)/../../common \
+ -I$(srcdir)/../../crypto \
+ -I$(srcdir)/../../object_store \
+ -I$(srcdir)/../../pkcs11 \
+ -I$(srcdir)/../../session_mgr \
+ -I$(srcdir)/../../slot_mgr \
+ @CPPUNIT_CFLAGS@ \
+ @CRYPTO_INCLUDES@
+
+check_PROGRAMS = datamgrtest
+
+datamgrtest_SOURCES = datamgrtest.cpp \
+ ByteStringTests.cpp \
+ RFC4880Tests.cpp \
+ SecureDataMgrTests.cpp
+
+datamgrtest_LDADD = ../../libsofthsm_convarch.la
+
+datamgrtest_LDFLAGS = @CRYPTO_LIBS@ @CPPUNIT_LIBS@ -no-install
+
+TESTS = datamgrtest
+
+EXTRA_DIST = $(srcdir)/*.h
diff --git a/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp
new file mode 100644
index 0000000..6fcfd94
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ RFC4880Tests.cpp
+
+ Contains test cases to test the RFC4880 implementation
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "RFC4880Tests.h"
+#include "RFC4880.h"
+#include "ByteString.h"
+#include "CryptoFactory.h"
+#include "AESKey.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RFC4880Tests);
+
+void RFC4880Tests::setUp()
+{
+ CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL);
+}
+
+void RFC4880Tests::tearDown()
+{
+}
+
+void RFC4880Tests::testRFC4880()
+{
+ const unsigned char* pwd1String = (const unsigned char*) "monkey";
+ const unsigned char* pwd2String = (const unsigned char*) "bicycle";
+ ByteString pwd1(pwd1String, strlen("monkey"));
+ ByteString pwd2(pwd2String, strlen("bicycle"));
+
+ // Generate salt and make sure that two different salt values are generated and
+ // that the last byte is also different (resulting in a different iteration jitter
+ // when computing a PBE key using both salt values)
+ ByteString salt1, salt2;
+
+ do
+ {
+ CPPUNIT_ASSERT(rng->generateRandom(salt1, 8) && rng->generateRandom(salt2, 8));
+ }
+ while ((salt1 == salt2) || (salt1[salt1.size() - 1] == salt2[salt2.size() - 1]));
+
+ // Create a password-based encryption key from the first and second password
+ AESKey* key1;
+ AESKey* key2;
+
+ CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd1, salt1, &key1));
+ CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd2, salt2, &key2));
+
+ // Check that the output keys differ and have the correct length
+ CPPUNIT_ASSERT(key1->getKeyBits().size() == 32);
+ CPPUNIT_ASSERT(key2->getKeyBits().size() == 32);
+ CPPUNIT_ASSERT(key1->getKeyBits() != key2->getKeyBits());
+
+ // Rederive the keys to check that the same output is generated every time
+ AESKey* key1_;
+ AESKey* key2_;
+
+ CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd1, salt1, &key1_));
+ CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd2, salt2, &key2_));
+
+ CPPUNIT_ASSERT(key1->getKeyBits() == key1_->getKeyBits());
+ CPPUNIT_ASSERT(key2->getKeyBits() == key2_->getKeyBits());
+
+ // Now reverse the salts and derive new keys
+ AESKey* key3;
+ AESKey* key4;
+
+ CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd1, salt2, &key3));
+ CPPUNIT_ASSERT(RFC4880::PBEDeriveKey(pwd2, salt1, &key4));
+
+ // Check that the keys are different and that they differ from the
+ // original keys (because different salts were used)
+ CPPUNIT_ASSERT(key3->getKeyBits() != key4->getKeyBits());
+ CPPUNIT_ASSERT(key1->getKeyBits() != key3->getKeyBits());
+ CPPUNIT_ASSERT(key1->getKeyBits() != key4->getKeyBits());
+ CPPUNIT_ASSERT(key2->getKeyBits() != key3->getKeyBits());
+ CPPUNIT_ASSERT(key2->getKeyBits() != key4->getKeyBits());
+
+ // Clean up
+ delete key1;
+ delete key2;
+ delete key1_;
+ delete key2_;
+ delete key3;
+ delete key4;
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.h
new file mode 100644
index 0000000..4663626
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/RFC4880Tests.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.
+ */
+
+/*****************************************************************************
+ RFC4880Tests.h
+
+ Contains test cases to test the RFC4880 implementation
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_RFC4880TESTS_H
+#define _SOFTHSM_V2_RFC4880TESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "RNG.h"
+
+class RFC4880Tests : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(RFC4880Tests);
+ CPPUNIT_TEST(testRFC4880);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void testRFC4880();
+
+ void setUp();
+ void tearDown();
+
+private:
+ RNG* rng;
+};
+
+#endif // !_SOFTHSM_V2_RFC4880TESTS_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp
new file mode 100644
index 0000000..7ef4816
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.cpp
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+/*****************************************************************************
+ SecureDataMgrTests.cpp
+
+ Contains test cases to test the secure data manager
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include "SecureDataMgrTests.h"
+#include "SecureDataManager.h"
+#include "CryptoFactory.h"
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SecureDataMgrTests);
+
+void SecureDataMgrTests::setUp()
+{
+ CPPUNIT_ASSERT((rng = CryptoFactory::i()->getRNG()) != NULL);
+}
+
+void SecureDataMgrTests::tearDown()
+{
+}
+
+void SecureDataMgrTests::testSecureDataManager()
+{
+ ByteString soPIN = "3132333435363738"; // "12345678"
+ ByteString userPIN = "4041424344454647"; // "ABCDEFGH"
+ ByteString newSOPIN = "3837363534333231"; // "87654321"
+ ByteString newUserPIN = "4746454443424140"; // "HGFEDCBA"
+
+ // Instantiate a blank secure data manager
+ SecureDataManager s1;
+ ByteString plaintext = "010203040506070809";
+ ByteString emptyPlaintext = "";
+ ByteString encrypted;
+
+ // Verify that no function other than setting the SO PIN works
+ CPPUNIT_ASSERT(!s1.setUserPIN(userPIN));
+ CPPUNIT_ASSERT(!s1.loginSO(soPIN));
+ CPPUNIT_ASSERT(!s1.loginUser(userPIN));
+ CPPUNIT_ASSERT(!s1.reAuthenticateSO(soPIN));
+ CPPUNIT_ASSERT(!s1.reAuthenticateUser(userPIN));
+ CPPUNIT_ASSERT(!s1.encrypt(plaintext, encrypted));
+ CPPUNIT_ASSERT(!s1.decrypt(encrypted, plaintext));
+ CPPUNIT_ASSERT(s1.getSOPINBlob().size() == 0);
+ CPPUNIT_ASSERT(s1.getUserPINBlob().size() == 0);
+
+ // Now set the SO PIN
+ CPPUNIT_ASSERT(s1.setSOPIN(soPIN));
+
+ // Check that it is still not possible to set the user PIN
+ CPPUNIT_ASSERT(!s1.setUserPIN(userPIN));
+
+ // Check that it is possible to log in with the SO PIN
+ CPPUNIT_ASSERT(s1.loginSO(soPIN));
+
+ // Check that it is now possible to also set the user PIN
+ CPPUNIT_ASSERT(s1.setUserPIN(userPIN));
+
+ // Check that is is now also possible to log in with the user PIN
+ CPPUNIT_ASSERT(s1.loginUser(userPIN));
+
+ // Check that it is possible to encrypt and decrypt some data
+ ByteString decrypted;
+
+ CPPUNIT_ASSERT(s1.encrypt(plaintext, encrypted));
+ CPPUNIT_ASSERT(encrypted != plaintext);
+
+ CPPUNIT_ASSERT(s1.decrypt(encrypted, decrypted));
+ CPPUNIT_ASSERT(decrypted == plaintext);
+
+ // Log out
+ s1.logout();
+
+ // Check that it is no longer possible to set the SO PIN
+ CPPUNIT_ASSERT(!s1.setSOPIN(soPIN));
+
+ // Check that it is no longer possible to set the user PIN
+ CPPUNIT_ASSERT(!s1.setUserPIN(userPIN));
+
+ // Check that encrypting/decrypting no longer works
+ CPPUNIT_ASSERT(!s1.encrypt(plaintext, encrypted));
+ CPPUNIT_ASSERT(!s1.decrypt(encrypted, plaintext));
+
+ // Export the key blobs
+ ByteString soPINBlob = s1.getSOPINBlob();
+ ByteString userPINBlob = s1.getUserPINBlob();
+
+ // Create a new instance with the exported key blobs
+ SecureDataManager s2(soPINBlob, userPINBlob);
+
+ // Check that the key blobs match
+ CPPUNIT_ASSERT(s1.getSOPINBlob() == s2.getSOPINBlob());
+ CPPUNIT_ASSERT(s1.getUserPINBlob() == s2.getUserPINBlob());
+
+ // Check that it is not possible to set the SO PIN
+ CPPUNIT_ASSERT(!s2.setSOPIN(soPIN));
+
+ // Check that it is possible to log in with the SO PIN
+ CPPUNIT_ASSERT(s2.loginSO(soPIN));
+
+ // Check that is is now also possible to log in with the user PIN
+ CPPUNIT_ASSERT(s2.loginUser(userPIN));
+
+ // Check that encrypting the data results in different ciphertext because of the random IV
+ ByteString encrypted2;
+
+ CPPUNIT_ASSERT(s2.encrypt(plaintext, encrypted2));
+ CPPUNIT_ASSERT(encrypted != encrypted2);
+
+ // Check that decrypting earlier data can be done with the recreated key
+ CPPUNIT_ASSERT(s2.decrypt(encrypted, decrypted));
+ CPPUNIT_ASSERT(decrypted == plaintext);
+
+ // Log in with the SO PIN
+ CPPUNIT_ASSERT(s2.loginSO(soPIN));
+
+ // Check that the SO PIN can be changed
+ CPPUNIT_ASSERT(s2.setSOPIN(newSOPIN));
+
+ // Check that it is no longer possible to log in with the old SO PIN
+ CPPUNIT_ASSERT(!s2.loginSO(soPIN));
+
+ // Check that encrypting/decrypting no longer works
+ CPPUNIT_ASSERT(!s2.encrypt(plaintext, encrypted));
+ CPPUNIT_ASSERT(!s2.decrypt(encrypted, plaintext));
+
+ // Check that the key blobs differ
+ CPPUNIT_ASSERT(s1.getSOPINBlob() != s2.getSOPINBlob());
+
+ // Check that it is possible to log in with the new SO PIN
+ CPPUNIT_ASSERT(s2.loginSO(newSOPIN));
+
+ // Log in with the user PIN
+ CPPUNIT_ASSERT(s2.loginUser(userPIN));
+
+ // Check that it is possible to change the user PIN
+ CPPUNIT_ASSERT(s2.setUserPIN(newUserPIN));
+
+ // Check that it is no longer possible to log in with the old user PIN
+ CPPUNIT_ASSERT(!s2.loginUser(userPIN));
+
+ // Check that encrypting/decrypting no longer works
+ CPPUNIT_ASSERT(!s2.encrypt(plaintext, encrypted));
+ CPPUNIT_ASSERT(!s2.decrypt(encrypted, plaintext));
+
+ // Check that it is possible to log in with the new user PIN
+ CPPUNIT_ASSERT(s2.loginUser(newUserPIN));
+
+ // Check that encrypting the data results in the different ciphertext because of the random IV
+ CPPUNIT_ASSERT(s2.encrypt(plaintext, encrypted2));
+ CPPUNIT_ASSERT(encrypted != encrypted2);
+
+ // Check that decrypting earlier data can be done with the recreated key
+ CPPUNIT_ASSERT(s2.decrypt(encrypted, decrypted));
+ CPPUNIT_ASSERT(decrypted == plaintext);
+
+ // Check that empty plaintext can be handled
+ CPPUNIT_ASSERT(s2.encrypt(emptyPlaintext, encrypted));
+ CPPUNIT_ASSERT(s2.decrypt(encrypted, decrypted));
+ CPPUNIT_ASSERT(decrypted == emptyPlaintext);
+
+ // Check that is is possible to log in with the SO PIN and re-authenticate
+ CPPUNIT_ASSERT(s1.loginSO(soPIN));
+ CPPUNIT_ASSERT(!s1.reAuthenticateSO(userPIN));
+ CPPUNIT_ASSERT(s1.reAuthenticateSO(soPIN));
+
+ // Check that is is possible to log in with the user PIN and re-authenticate
+ CPPUNIT_ASSERT(s1.loginUser(userPIN));
+ CPPUNIT_ASSERT(!s1.reAuthenticateUser(soPIN));
+ CPPUNIT_ASSERT(s1.reAuthenticateUser(userPIN));
+
+ // Check that it is possible to encrypt and decrypt some data
+ CPPUNIT_ASSERT(s1.encrypt(plaintext, encrypted));
+ CPPUNIT_ASSERT(encrypted != plaintext);
+
+ CPPUNIT_ASSERT(s1.decrypt(encrypted, decrypted));
+ CPPUNIT_ASSERT(decrypted == plaintext);
+}
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.h
new file mode 100644
index 0000000..743a01b
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/SecureDataMgrTests.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.
+ */
+
+/*****************************************************************************
+ SecureDataMgrTests.h
+
+ Contains test cases to test the secure data manager
+ *****************************************************************************/
+
+#ifndef _SOFTHSM_V2_SECUREDATAMGRTESTS_H
+#define _SOFTHSM_V2_SECUREDATAMGRTESTS_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include "RNG.h"
+
+class SecureDataMgrTests : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(SecureDataMgrTests);
+ CPPUNIT_TEST(testSecureDataManager);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void testSecureDataManager();
+
+ void setUp();
+ void tearDown();
+
+private:
+ RNG* rng;
+};
+
+#endif // !_SOFTHSM_V2_SECUREDATAMGRTESTS_H
+
diff --git a/SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp b/SoftHSMv2/src/lib/data_mgr/test/datamgrtest.cpp
new file mode 100644
index 0000000..49fa535
--- /dev/null
+++ b/SoftHSMv2/src/lib/data_mgr/test/datamgrtest.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.
+ */
+
+/*****************************************************************************
+ datamgrtest.cpp
+
+ The main test executor for tests on the secure data manager 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 &registry = 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;
+}