diff options
Diffstat (limited to 'SoftHSMv2/src/lib/data_mgr')
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 ®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; +} |